diff --git a/BUILD.gn b/BUILD.gn index e36ea3dc9fdfbf12e46e1fb41b01d6e91b4f7ab7..c34324ab1b2b85e3236647c4392b1d3d9ecbcf50 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -252,6 +252,11 @@ config("container_config") { "-DLOSCFG_TIME_CONTAINER", "-DLOSCFG_USER_CONTAINER", "-DLOSCFG_PROC_PROCESS_DIR", + "-DLOSCFG_KERNEL_PLIMITS", + "-DLOSCFG_KERNEL_MEM_PLIMIT", + "-DLOSCFG_KERNEL_IPC_PLIMIT", + "-DLOSCFG_KERNEL_DEV_PLIMIT", + "-DLOSCFG_KERNEL_SCHED_PLIMIT", ] } } diff --git a/compat/posix/src/mqueue.c b/compat/posix/src/mqueue.c index ab22c404bf79892c1d582d681583d9c0c8b6f12b..0b885d8618ec6d5abdc65c6d9828e0d3c9d684b8 100644 --- a/compat/posix/src/mqueue.c +++ b/compat/posix/src/mqueue.c @@ -113,7 +113,9 @@ STATIC INLINE struct mqarray *GetMqueueCBByName(const CHAR *name) STATIC INT32 DoMqueueDelete(struct mqarray *mqueueCB) { UINT32 ret; - +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + OsIPCLimitMqFree(); +#endif if (mqueueCB->mq_name != NULL) { LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name); mqueueCB->mq_name = NULL; @@ -163,11 +165,29 @@ STATIC int SaveMqueueName(const CHAR *mqName, struct mqarray *mqueueCB) return LOS_OK; } +STATIC VOID MqueueCBInit(struct mqarray *mqueueCB, const struct mq_attr *attr, INT32 openFlag, UINT32 mode) +{ + mqueueCB->unlinkflag = FALSE; + mqueueCB->unlink_ref = 0; + mqueueCB->mq_personal->mq_status = MQ_USE_MAGIC; + mqueueCB->mq_personal->mq_next = NULL; + mqueueCB->mq_personal->mq_posixdes = mqueueCB; + mqueueCB->mq_personal->mq_flags = (INT32)((UINT32)openFlag | ((UINT32)attr->mq_flags & (UINT32)FNONBLOCK)); + mqueueCB->mq_personal->mq_mode = mode; + mqueueCB->mq_personal->mq_refcount = 0; + mqueueCB->mq_notify.pid = 0; +} + STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR *mqName, INT32 openFlag, UINT32 mode) { struct mqarray *mqueueCB = NULL; UINT32 mqueueID; +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + if (OsIPCLimitMqAlloc() != LOS_OK) { + return (struct mqpersonal *)-1; + } +#endif UINT32 err = LOS_QueueCreate(NULL, attr->mq_maxmsg, &mqueueID, 0, attr->mq_msgsize); if (map_errno(err) != ENOERR) { goto ERROUT; @@ -201,15 +221,7 @@ STATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR goto ERROUT; } - mqueueCB->unlinkflag = FALSE; - mqueueCB->unlink_ref = 0; - mqueueCB->mq_personal->mq_status = MQ_USE_MAGIC; - mqueueCB->mq_personal->mq_next = NULL; - mqueueCB->mq_personal->mq_posixdes = mqueueCB; - mqueueCB->mq_personal->mq_flags = (INT32)((UINT32)openFlag | ((UINT32)attr->mq_flags & (UINT32)FNONBLOCK)); - mqueueCB->mq_personal->mq_mode = mode; - mqueueCB->mq_personal->mq_refcount = 0; - mqueueCB->mq_notify.pid = 0; + MqueueCBInit(mqueueCB, attr, openFlag, mode); return mqueueCB->mq_personal; ERROUT: @@ -218,6 +230,9 @@ ERROUT: LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name); mqueueCB->mq_name = NULL; } +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + OsIPCLimitMqFree(); +#endif return (struct mqpersonal *)-1; } diff --git a/fs/proc/BUILD.gn b/fs/proc/BUILD.gn index c0d3c9689a713b4e8f7e635c0dafb665fcc1f41f..bbeece87cd4065ddbc481b163cad6beed968c77e 100644 --- a/fs/proc/BUILD.gn +++ b/fs/proc/BUILD.gn @@ -38,6 +38,7 @@ kernel_module(module_name) { "os_adapt/fs_cache_proc.c", "os_adapt/mem_info.c", "os_adapt/mounts_proc.c", + "os_adapt/plimits_proc.c", "os_adapt/power_proc.c", "os_adapt/proc_init.c", "os_adapt/proc_vfs.c", diff --git a/fs/proc/include/internal.h b/fs/proc/include/internal.h index 861d12d8eefa238334c1a02db5501239a741102b..a041a31aee962db7990df07ef3c1e0c1a1b599be 100644 --- a/fs/proc/include/internal.h +++ b/fs/proc/include/internal.h @@ -55,6 +55,16 @@ void ProcSysMemInfoInit(void); void ProcFileSysInit(void); #endif +#ifdef LOSCFG_KERNEL_PLIMITS +void ProcLimitsInit(void); +#endif + +void ProcEntryClearVnode(struct ProcDirEntry *entry); + +void ProcDetachNode(struct ProcDirEntry *pn); + +void RemoveProcEntryTravalsal(struct ProcDirEntry *pn); + void ProcPmInit(void); void ProcVmmInit(void); diff --git a/fs/proc/include/proc_fs.h b/fs/proc/include/proc_fs.h index 022d92acf4292d62e144b35ec3be0a858a5e20b0..f172d439b5d10c67d542397e41c22a3fdf315f5a 100644 --- a/fs/proc/include/proc_fs.h +++ b/fs/proc/include/proc_fs.h @@ -93,6 +93,15 @@ struct ProcFileOperations { ssize_t (*readLink)(struct ProcDirEntry *pde, char *buf, size_t bufLen); }; +#ifdef LOSCFG_KERNEL_PLIMITS +struct ProcDirOperations { + int (*rmdir)(struct ProcDirEntry *parent, struct ProcDirEntry *pde, const char *name); + int (*mkdir)(struct ProcDirEntry *parent, const char *dirName, mode_t mode, struct ProcDirEntry **pde); +}; +#endif + +#define PROC_DATA_STATIC 0 +#define PROC_DATA_FREE 1 struct ProcDirEntry { uint uid; uint gid; @@ -101,6 +110,10 @@ struct ProcDirEntry { const struct ProcFileOperations *procFileOps; struct ProcFile *pf; struct ProcDirEntry *next, *parent, *subdir; +#ifdef LOSCFG_KERNEL_PLIMITS + const struct ProcDirOperations *procDirOps; +#endif + int dataType; void *data; atomic_t count; /* open file count */ spinlock_t pdeUnloadLock; @@ -111,6 +124,11 @@ struct ProcDirEntry { enum VnodeType type; }; +struct ProcDataParm { + void *data; + int dataType; +}; + struct ProcFile { fmode_t fMode; spinlock_t fLock; @@ -274,7 +292,7 @@ extern struct ProcDirEntry *ProcCreate(const char *name, mode_t mode, * */ extern struct ProcDirEntry *ProcCreateData(const char *name, mode_t mode, struct ProcDirEntry *parent, - const struct ProcFileOperations *procFileOps, void *data); + const struct ProcFileOperations *procFileOps, struct ProcDataParm *param); /** * @ingroup procfs * @brief init proc fs diff --git a/fs/proc/os_adapt/plimits_proc.c b/fs/proc/os_adapt/plimits_proc.c new file mode 100644 index 0000000000000000000000000000000000000000..0782cbe69da116fcd49194a120e5953a1a5b0df7 --- /dev/null +++ b/fs/proc/os_adapt/plimits_proc.c @@ -0,0 +1,1071 @@ +/* + * Copyright (c) 2023-2023 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 +#include +#include +#include "stdlib.h" +#include "los_printf.h" +#include "los_base.h" +#include "los_seq_buf.h" +#include "internal.h" +#include "proc_fs.h" +#include "los_task_pri.h" +#include "los_process_pri.h" +#include "los_process.h" +#include "show.h" +#include "vnode.h" +#include "proc_file.h" +#include "user_copy.h" + +#ifdef LOSCFG_KERNEL_PLIMITS +#include "los_plimits.h" + +#define PLIMITS_ENTRY_NAME_MAX 64 +#define PLIMITERSET_DELETE_ALLOC 4 +#define UNITPTR_NULL ((uintptr_t)(0xFFFFFFFF)) +#define PLIMIT_FILE_MODE_READ_WRITE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) +#define PLIMIT_FILE_MODE_READ_ONLY (S_IRUSR | S_IRGRP | S_IROTH) +#define PLIMIT_FILE_MODE_WRITE_ONLY (S_IWUSR) +#define PLIMIT_FILE_MODE_MASK_WRITE (~((mode_t)(S_IWUSR))) +#define PLIMIT_FILE_MODE_MASK_NONE (~((mode_t)(0))) +#define LOS_MAX_CACHE (UINT64)(0xFFFFFFFFFFFFFFFF) +#define PLIMIT_CAT_BUF_SIZE 512 +#define MAX_PROTECTED_PROCESS_ID 14 +#define UNITPTR_NULL ((uintptr_t)(0xFFFFFFFF)) + +static int ShowPids(struct SeqBuf *seqBuf, VOID *data); +static ssize_t PidMigrateFromProcLimiterSet(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t PidLimitReadPidLimit(struct SeqBuf *seqBuf, VOID *data); +static ssize_t PidLimitReadPriorityLimit(struct SeqBuf *seqBuf, VOID *data); +static ssize_t PriorityLimitVariableWrite(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t PidsMaxVariableWrite(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t ProcLimitsShowLimiters(struct SeqBuf *seqBuf, VOID *data); +static ssize_t ProcLimitsDeleteLimiters(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t ProcLimitsAddLimiters(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static int ProcfsPlimitsMkdir(struct ProcDirEntry *parent, const char *dirName, mode_t mode, struct ProcDirEntry **pde); +static int ProcfsPlimitsRmdir(struct ProcDirEntry *parent, struct ProcDirEntry *pde, const char *name); +#ifdef LOSCFG_KERNEL_MEM_PLIMIT +static ssize_t MemLimitReadLimit(struct SeqBuf *seqBuf, VOID *data); +static ssize_t MemLimitWriteLimit(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t MemLimitStatShow(struct SeqBuf *seqBuf, VOID *data); +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT +static ssize_t IPCLimitReadMqLimit(struct SeqBuf *seqBuf, VOID *data); +static ssize_t IPCLimitWriteMqLimit(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t IPCLimitReadShmLimit(struct SeqBuf *seqBuf, VOID *data); +static ssize_t IPCLimitWriteShmLimit(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t IPCLimitShowStat(struct SeqBuf *seqBuf, VOID *data); +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT +static ssize_t DevLimitWriteAllow(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t DevLimitWriteDeny(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t DevLimitShow(struct SeqBuf *seqBuf, VOID *data); +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT +static ssize_t SchedLimitReadPeriod(struct SeqBuf *seqBuf, VOID *data); +static ssize_t SchedLimitWritePeriod(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t SchedLimitReadQuota(struct SeqBuf *seqBuf, VOID *data); +static ssize_t SchedLimitWriteQuota(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos); +static ssize_t SchedLimitShow(struct SeqBuf *seqBuf, VOID *data); +#endif + +struct PLimitsEntryOpt { + int id; + char name[PLIMITS_ENTRY_NAME_MAX]; + mode_t mode; + uintptr_t offset; + struct ProcFileOperations ops; +}; + +static struct ProcDirOperations g_procDirOperations = { + .mkdir = ProcfsPlimitsMkdir, + .rmdir = ProcfsPlimitsRmdir, +}; + +static struct PLimitsEntryOpt g_plimitsEntryOpts[] = { + { + .id = PROCESS_LIMITER_COUNT, + .name = "plimits.limiters", + .mode = PLIMIT_FILE_MODE_READ_ONLY, + .offset = UNITPTR_NULL, + .ops = { + .read = ProcLimitsShowLimiters, + } + }, + { + .id = PROCESS_LIMITER_COUNT, + .name = "plimits.limiter_add", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = UNITPTR_NULL, + .ops = { + .write = ProcLimitsAddLimiters, + }, + }, + { + .id = PROCESS_LIMITER_COUNT, + .name = "plimits.limiter_delete", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = UNITPTR_NULL, + .ops = { + .write = ProcLimitsDeleteLimiters, + }, + }, + { + .id = PROCESS_LIMITER_COUNT, + .name = "plimits.procs", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = UNITPTR_NULL, + .ops = { + .read = ShowPids, + .write = PidMigrateFromProcLimiterSet, + }, + }, + { + .id = PROCESS_LIMITER_ID_PIDS, + .name = "pids.max", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = 0, + .ops = { + .read = PidLimitReadPidLimit, + .write = PidsMaxVariableWrite, + }, + }, + { + .id = PROCESS_LIMITER_ID_PIDS, + .name = "pids.priority", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = 0, + .ops = { + .read = PidLimitReadPriorityLimit, + .write = PriorityLimitVariableWrite, + }, + }, +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + { + .id = PROCESS_LIMITER_ID_MEM, + .name = "memory.limit", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = 0, + .ops = { + .read = MemLimitReadLimit, + .write = MemLimitWriteLimit, + }, + }, + { + .id = PROCESS_LIMITER_ID_MEM, + .name = "memory.stat", + .mode = PLIMIT_FILE_MODE_READ_ONLY, + .offset = UNITPTR_NULL, + .ops = { + .read = MemLimitStatShow, + } + }, +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + { + .id = PROCESS_LIMITER_ID_IPC, + .name = "ipc.mq_limit", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = 0, + .ops = { + .read = IPCLimitReadMqLimit, + .write = IPCLimitWriteMqLimit, + } + }, + { + .id = PROCESS_LIMITER_ID_IPC, + .name = "ipc.shm_limit", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = 0, + .ops = { + .read = IPCLimitReadShmLimit, + .write = IPCLimitWriteShmLimit, + } + }, + { + .id = PROCESS_LIMITER_ID_IPC, + .name = "ipc.stat", + .mode = PLIMIT_FILE_MODE_READ_ONLY, + .offset = UNITPTR_NULL, + .ops = { + .read = IPCLimitShowStat, + } + }, +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT + { + .id = PROCESS_LIMITER_ID_DEV, + .name = "devices.allow", + .mode = PLIMIT_FILE_MODE_WRITE_ONLY, + .offset = UNITPTR_NULL, + .ops = { + .write = DevLimitWriteAllow, + } + }, + { + .id = PROCESS_LIMITER_ID_DEV, + .name = "devices.deny", + .mode = PLIMIT_FILE_MODE_WRITE_ONLY, + .offset = UNITPTR_NULL, + .ops = { + .write = DevLimitWriteDeny, + } + }, + { + .id = PROCESS_LIMITER_ID_DEV, + .name = "devices.list", + .mode = PLIMIT_FILE_MODE_READ_ONLY, + .offset = 0, + .ops = { + .read = DevLimitShow, + } + }, +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + { + .id = PROCESS_LIMITER_ID_SCHED, + .name = "sched.period", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = 0, + .ops = { + .read = SchedLimitReadPeriod, + .write = SchedLimitWritePeriod, + }, + }, + { + .id = PROCESS_LIMITER_ID_SCHED, + .name = "sched.quota", + .mode = PLIMIT_FILE_MODE_READ_WRITE, + .offset = 0, + .ops = { + .read = SchedLimitReadQuota, + .write = SchedLimitWriteQuota, + }, + }, + { + .id = PROCESS_LIMITER_ID_SCHED, + .name = "sched.stat", + .mode = PLIMIT_FILE_MODE_READ_ONLY, + .offset = UNITPTR_NULL, + .ops = { + .read = SchedLimitShow, + } + }, +#endif +}; + +static unsigned int MemUserCopy(const char *src, size_t len, char **kbuf) +{ + if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)src, len)) { + char *kernelBuf = LOS_MemAlloc(m_aucSysMem1, len + 1); + if (kernelBuf == NULL) { + return ENOMEM; + } + + if (LOS_ArchCopyFromUser(kernelBuf, src, len) != 0) { + (VOID)LOS_MemFree(m_aucSysMem1, kernelBuf); + return EFAULT; + } + kernelBuf[len] = '\0'; + *kbuf = kernelBuf; + return 0; + } + return 0; +} + +static inline struct ProcDirEntry *GetCurrDirectory(struct ProcDirEntry *dirEntry) +{ + return ((dirEntry == NULL) || S_ISDIR(dirEntry->mode)) ? dirEntry : dirEntry->parent; +} + +static inline ProcLimiterSet *GetProcLimiterSetFromDirEntry(struct ProcDirEntry *dirEntry) +{ + struct ProcDirEntry *currDirectory = GetCurrDirectory(dirEntry); + return (currDirectory == NULL) || (currDirectory->data == NULL) ? NULL : (ProcLimiterSet *)currDirectory->data; +} + +static struct ProcDirEntry *ProcCreateLimiterFiles(struct ProcDirEntry *parentEntry, + struct PLimitsEntryOpt *entryOpt, + mode_t mode, void *data) +{ + struct ProcDataParm dataParm = { + .data = data, + .dataType = PROC_DATA_STATIC, + }; + struct ProcDirEntry *plimitFile = ProcCreateData(entryOpt->name, entryOpt->mode & mode, parentEntry, + &entryOpt->ops, &dataParm); + if (plimitFile == NULL) { + return NULL; + } + return plimitFile; +} + +static void ProcLimiterDirEntryInit(struct ProcDirEntry *dirEntry, unsigned mask, mode_t mode) +{ + struct ProcDirEntry *currDir = GetCurrDirectory(dirEntry); + if (currDir == NULL) { + return; + } + + ProcLimiterSet *plimiterData = (ProcLimiterSet *)currDir->data; + if (plimiterData == NULL) { + return; + } + + for (int index = 0; index < (sizeof(g_plimitsEntryOpts) / sizeof(struct PLimitsEntryOpt)); index++) { + struct PLimitsEntryOpt *entryOpt = &g_plimitsEntryOpts[index]; + enum ProcLimiterID plimiterType = entryOpt->id; + if (!(BIT(plimiterType) & mask)) { + continue; + } + + void *head = (entryOpt->offset == UNITPTR_NULL) ? + plimiterData : (void *)plimiterData->limitsList[plimiterType]; + struct ProcDirEntry *entry = ProcCreateLimiterFiles(currDir, entryOpt, mode, head); + if (entry == NULL) { + RemoveProcEntry(currDir->name, NULL); + return; + } + } + return; +} + +static ssize_t PLimitsCopyLimits(struct ProcDirEntry *dirEntry) +{ + struct ProcDirEntry *parentPde = dirEntry->parent; + ProcLimiterSet *parentPLimits = (ProcLimiterSet *)parentPde->data; + if (parentPLimits == NULL) { + return -EINVAL; + } + + ProcLimiterSet *newPLimits = OsPLimitsCreate(parentPLimits); + if (newPLimits == NULL) { + return -ENOMEM; + } + dirEntry->data = (VOID *)newPLimits; + dirEntry->dataType = PROC_DATA_STATIC; + dirEntry->procDirOps = parentPde->procDirOps; + ProcLimiterDirEntryInit(dirEntry, newPLimits->mask, PLIMIT_FILE_MODE_MASK_NONE); + return 0; +} + +static int ProcfsPlimitsMkdir(struct ProcDirEntry *parent, const char *dirName, mode_t mode, struct ProcDirEntry **pde) +{ + int ret; + if (strcmp(parent->name, "plimits") != 0) { + return -EPERM; + } + + struct ProcDirEntry *plimitDir = ProcCreateData(dirName, S_IFDIR | mode, parent, NULL, NULL); + if (plimitDir == NULL) { + return -EINVAL; + } + + ret = PLimitsCopyLimits(plimitDir); + if (ret != LOS_OK) { + ProcFreeEntry(plimitDir); + return -ENOSYS; + } + *pde = plimitDir; + return ret; +} + +static int ProcfsPlimitsRmdir(struct ProcDirEntry *parent, struct ProcDirEntry *pde, const char *name) +{ + if (pde == NULL) { + return -EINVAL; + } + + ProcLimiterSet *plimits = GetProcLimiterSetFromDirEntry(pde); + pde->data = NULL; + + unsigned ret = OsPLimitsFree(plimits); + if (ret != 0) { + pde->data = plimits; + return -ret; + } + + spin_lock(&procfsLock); + ProcDetachNode(pde); + spin_unlock(&procfsLock); + + RemoveProcEntryTravalsal(pde->subdir); + + ProcFreeEntry(pde); + return 0; +} + +static ssize_t ProcLimitsShowLimiters(struct SeqBuf *seqBuf, VOID *data) +{ + ProcLimiterSet *plimits = (ProcLimiterSet *)data; + UINT32 mask; + if (plimits == NULL) { + return -LOS_NOK; + } + mask = plimits->mask; + + if (mask & BIT(PROCESS_LIMITER_ID_PIDS)) { + LosBufPrintf(seqBuf, "%s ", "pids"); + } +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + if (mask & BIT(PROCESS_LIMITER_ID_MEM)) { + LosBufPrintf(seqBuf, "%s ", "memory"); + } +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + if (mask & BIT(PROCESS_LIMITER_ID_IPC)) { + LosBufPrintf(seqBuf, "%s ", "ipc"); + } +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT + if (mask & BIT(PROCESS_LIMITER_ID_DEV)) { + LosBufPrintf(seqBuf, "%s ", "devices"); + } +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + if (mask & BIT(PROCESS_LIMITER_ID_SCHED)) { + LosBufPrintf(seqBuf, "%s ", "sched"); + } +#endif + return LOS_OK; +} + +static ssize_t ProcLimitsAddLimiters(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (VOID)ppos; + unsigned int ret; + struct ProcDirEntry *dirEntry = pf->pPDE; + ProcLimiterSet *plimits = GetProcLimiterSetFromDirEntry(dirEntry); + char *kbuf = NULL; + + ret = MemUserCopy(buf, count, &kbuf); + if (ret != 0) { + return -ret; + } else if ((ret == 0) && (kbuf != NULL)) { + buf = (const char *)kbuf; + } + + enum ProcLimiterID procLimiterID = 0; + if (strcmp(buf, "pids") == 0) { + procLimiterID = PROCESS_LIMITER_ID_PIDS; +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + } else if (strcmp(buf, "memory") == 0) { + procLimiterID = PROCESS_LIMITER_ID_MEM; +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + } else if (strcmp(buf, "ipc") == 0) { + procLimiterID = PROCESS_LIMITER_ID_IPC; +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT + } else if (strcmp(buf, "devices") == 0) { + procLimiterID = PROCESS_LIMITER_ID_DEV; +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + } else if (strcmp(buf, "sched") == 0) { + procLimiterID = PROCESS_LIMITER_ID_SCHED; +#endif + } else { + (void)LOS_MemFree(m_aucSysMem1, kbuf); + PRINTK("enter error, please check the params.\n"); + return -EINVAL; + } + (void)LOS_MemFree(m_aucSysMem1, kbuf); + + ret = OsPLimitsAddLimiters(plimits, procLimiterID); + if (ret != LOS_OK) { + return -ret; + } + + ProcLimiterDirEntryInit(dirEntry, BIT(procLimiterID), PLIMIT_FILE_MODE_MASK_NONE); + return count; +} + +static struct ProcDirEntry *PLimitsProcFindEntry(const char *name, struct ProcDirEntry *parent) +{ + int len = strlen(name); + struct ProcDirEntry *pn = NULL; + for (pn = parent->subdir; pn != NULL; pn = pn->next) { + if (ProcMatch(len, name, pn)) { + break; + } + } + return pn; +} + +static int DeleteProcEntry(const char *buf, struct ProcDirEntry *currDirectory) +{ + struct ProcDirEntry *entry = PLimitsProcFindEntry(buf, currDirectory); + if (entry == NULL) { + return EINVAL; + } + ProcDetachNode(entry); + ProcEntryClearVnode(entry); + ProcFreeEntry(entry); + return 0; +} + +static int PLimitsDeleteProcEntry(enum ProcLimiterID procLimiterID, struct ProcDirEntry *currDirectory) +{ + for (int index = 0; index < (sizeof(g_plimitsEntryOpts) / sizeof(struct PLimitsEntryOpt)); index++) { + struct PLimitsEntryOpt *entryOpt = &g_plimitsEntryOpts[index]; + if (entryOpt->id != procLimiterID) { + continue; + } + (void)DeleteProcEntry(entryOpt->name, currDirectory); + } + return 0; +} + +static ssize_t ProcLimitsDeleteLimiters(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (VOID)ppos; + unsigned ret; + unsigned mask = 0; + enum ProcLimiterID procLimiterID = 0; + char *kbuf = NULL; + + if ((pf == NULL) || (pf->pPDE == NULL)) { + return -EINVAL; + } + + struct ProcDirEntry *pde = pf->pPDE; + struct ProcDirEntry *currDirectory = GetCurrDirectory(pde); + if ((currDirectory == NULL) || (currDirectory->data == NULL)) { + return -EINVAL; + } + ProcLimiterSet *plimits = (ProcLimiterSet *)currDirectory->data; + + ret = MemUserCopy(buf, count, &kbuf); + if (ret != 0) { + return -ret; + } else if ((ret == 0) && (kbuf != NULL)) { + buf = (const char *)kbuf; + } + + if (strcmp(buf, "pids") == 0) { + procLimiterID = PROCESS_LIMITER_ID_PIDS; +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + } else if (strcmp(buf, "memory") == 0) { + procLimiterID = PROCESS_LIMITER_ID_MEM; +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + } else if (strcmp(buf, "ipc") == 0) { + procLimiterID = PROCESS_LIMITER_ID_IPC; +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT + } else if (strcmp(buf, "devices") == 0) { + procLimiterID = PROCESS_LIMITER_ID_DEV; +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + } else if (strcmp(buf, "sched") == 0) { + procLimiterID = PROCESS_LIMITER_ID_SCHED; +#endif + } else { + PRINTK("the input information or format is incorrect.\n"); + (void)LOS_MemFree(m_aucSysMem1, kbuf); + return -EINVAL; + } + (void)LOS_MemFree(m_aucSysMem1, kbuf); + + ret = OsPLimitsDeleteLimiters(plimits, procLimiterID, &mask); + if (ret != LOS_OK) { + return -ret; + } + + PLimitsDeleteProcEntry(procLimiterID, currDirectory); + return count; +} + +#define PLIMITS_PID_STR_LENGTH 4 +static int ShowPids(struct SeqBuf *seqBuf, VOID *data) +{ + unsigned int size, pidMax; + if (data == NULL) { + return -EINVAL; + } + + const ProcLimiterSet *plimits = (const ProcLimiterSet *)data; + pidMax = LOS_GetSystemProcessMaximum(); + size = pidMax * sizeof(unsigned int); + unsigned int *pids = (unsigned int *)LOS_MemAlloc(m_aucSysMem1, size); + if (pids == NULL) { + return -ENOMEM; + } + (void)memset_s(pids, size, 0, size); + + unsigned int ret = OsPLimitsPidsGet(plimits, pids, size); + if (ret != LOS_OK) { + (VOID)LOS_MemFree(m_aucSysMem1, pids); + return -ret; + } + + (void)LosBufPrintf(seqBuf, "\n"); + for (unsigned int index = 0; index < pidMax; index++) { + if (pids[index] == 0) { + continue; + } + (void)LosBufPrintf(seqBuf, "%u ", index); + } + (void)LOS_MemFree(m_aucSysMem1, pids); + return 0; +} + +static long long int GetPidLimitValue(struct ProcFile *pf, const CHAR *buf, size_t count) +{ + long long int value; + char *kbuf = NULL; + + if ((pf == NULL) || (pf->pPDE == NULL) || (buf == NULL) || (count <= 0)) { + return -EINVAL; + } + + unsigned ret = MemUserCopy(buf, count, &kbuf); + if (ret != 0) { + return -ret; + } else if ((ret == 0) && (kbuf != NULL)) { + buf = (const char *)kbuf; + } + + if (strspn(buf, "0123456789") != count) { + (void)LOS_MemFree(m_aucSysMem1, kbuf); + return -EINVAL; + } + value = strtoll(buf, NULL, 10); /* 10: decimal */ + (void)LOS_MemFree(m_aucSysMem1, kbuf); + return value; +} + +static ssize_t PidMigrateFromProcLimiterSet(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (VOID)ppos; + unsigned ret; + + long long int pid = GetPidLimitValue(pf, buf, count); + if (pid < 0) { + return pid; + } + + ProcLimiterSet *plimits = GetCurrDirectory(pf->pPDE)->data; + ret = OsPLimitsAddPid(plimits, (unsigned int)pid); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t PidLimitReadPidLimit(struct SeqBuf *seqBuf, VOID *data) +{ + PidLimit *pidLimit = (PidLimit *)data; + if ((seqBuf == NULL) || (pidLimit == NULL)) { + return -EINVAL; + } + + (void)LosBufPrintf(seqBuf, "%u\n", pidLimit->pidLimit); + return 0; +} + +static ssize_t PidLimitReadPriorityLimit(struct SeqBuf *seqBuf, VOID *data) +{ + PidLimit *pidLimit = (PidLimit *)data; + if ((seqBuf == NULL) || (pidLimit == NULL)) { + return -EINVAL; + } + + (void)LosBufPrintf(seqBuf, "%u\n", pidLimit->priorityLimit); + return 0; +} + +static ssize_t PriorityLimitVariableWrite(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + long long int value = GetPidLimitValue(pf, buf, count); + if (value < 0) { + return value; + } + + PidLimit *pidLimit = (PidLimit *)pf->pPDE->data; + unsigned ret = PidLimitSetPriorityLimit(pidLimit, (unsigned)value); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t PidsMaxVariableWrite(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + long long int value = GetPidLimitValue(pf, buf, count); + if (value < 0) { + return value; + } + + PidLimit *pidLimit = (PidLimit *)pf->pPDE->data; + unsigned ret = PidLimitSetPidLimit(pidLimit, (unsigned)value); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +#ifdef LOSCFG_KERNEL_MEM_PLIMIT +static ssize_t MemLimitReadLimit(struct SeqBuf *seqBuf, VOID *data) +{ + ProcMemLimiter *memLimit = (ProcMemLimiter *)data; + if ((seqBuf == NULL) || (memLimit == NULL)) { + return -EINVAL; + } + + (void)LosBufPrintf(seqBuf, "%llu\n", memLimit->limit); + return 0; +} + +static ssize_t MemLimitWriteLimit(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + long long int value = GetPidLimitValue(pf, buf, count); + if (value < 0) { + return value; + } + + ProcMemLimiter *memLimit = (ProcMemLimiter *)pf->pPDE->data; + unsigned ret = OsMemLimitSetMemLimit(memLimit, (unsigned long long)value); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t MemLimitStatShow(struct SeqBuf *seqBuf, VOID *data) +{ + ProcLimiterSet *plimits = (ProcLimiterSet *)data; + if ((seqBuf == NULL) || (plimits == NULL)) { + return -EINVAL; + } + + UINT32 pidMax = LOS_GetSystemProcessMaximum(); + UINT32 size = sizeof(ProcMemLimiter) + pidMax * sizeof(unsigned long long); + unsigned long long *usage = (unsigned long long *)LOS_MemAlloc(m_aucSysMem1, size); + if (usage == NULL) { + return -ENOMEM; + } + (void)memset_s(usage, size, 0, size); + + unsigned int ret = OsPLimitsMemUsageGet(plimits, usage, size); + if (ret != LOS_OK) { + (VOID)LOS_MemFree(m_aucSysMem1, usage); + return -ret; + } + + ProcMemLimiter *memLimit = (ProcMemLimiter *)usage; + unsigned long long *memUsage = (unsigned long long *)((uintptr_t)usage + sizeof(ProcMemLimiter)); + (void)LosBufPrintf(seqBuf, "\nMem used: %llu\n", memLimit->usage); + (void)LosBufPrintf(seqBuf, "Mem peak: %llu\n", memLimit->peak); + (void)LosBufPrintf(seqBuf, "Mem failed count: %u\n", memLimit->failcnt); + + for (unsigned int index = 0; index < pidMax; index++) { + if (memUsage[index] == 0) { + continue; + } + (void)LosBufPrintf(seqBuf, "PID: %u mem used: %llu \n", index, memUsage[index]); + } + (void)LOS_MemFree(m_aucSysMem1, usage); + return 0; +} +#endif + +#ifdef LOSCFG_KERNEL_IPC_PLIMIT +static ssize_t IPCLimitReadMqLimit(struct SeqBuf *seqBuf, VOID *data) +{ + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)data; + if ((seqBuf == NULL) || (ipcLimit == NULL)) { + return -EINVAL; + } + + (void)LosBufPrintf(seqBuf, "%u\n", ipcLimit->mqCountLimit); + return 0; +} + +static ssize_t IPCLimitWriteMqLimit(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + long long int value = GetPidLimitValue(pf, buf, count); + if (value < 0) { + return value; + } + + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)pf->pPDE->data; + unsigned ret = OsIPCLimitSetMqLimit(ipcLimit, (unsigned long long)value); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t IPCLimitReadShmLimit(struct SeqBuf *seqBuf, VOID *data) +{ + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)data; + if ((seqBuf == NULL) || (ipcLimit == NULL)) { + return -EINVAL; + } + + (void)LosBufPrintf(seqBuf, "%u\n", ipcLimit->shmSizeLimit); + return 0; +} + +static ssize_t IPCLimitWriteShmLimit(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + long long int value = GetPidLimitValue(pf, buf, count); + if (value < 0) { + return value; + } + + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)pf->pPDE->data; + unsigned ret = OsIPCLimitSetShmLimit(ipcLimit, (unsigned long long)value); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t IPCLimitShowStat(struct SeqBuf *seqBuf, VOID *data) +{ + ProcLimiterSet *plimits = (ProcLimiterSet *)data; + if ((seqBuf == NULL) || (plimits == NULL)) { + return -EINVAL; + } + + unsigned int size = sizeof(ProcIPCLimit); + ProcIPCLimit *newIPCLimit = (ProcIPCLimit *)LOS_MemAlloc(m_aucSysMem1, size); + if (newIPCLimit == NULL) { + return -ENOMEM; + } + (void)memset_s(newIPCLimit, size, 0, size); + + unsigned int ret = OsPLimitsIPCStatGet(plimits, newIPCLimit, size); + if (ret != LOS_OK) { + (VOID)LOS_MemFree(m_aucSysMem1, newIPCLimit); + return -ret; + } + + (void)LosBufPrintf(seqBuf, "mq count: %u\n", newIPCLimit->mqCount); + (void)LosBufPrintf(seqBuf, "mq failed count: %u\n", newIPCLimit->mqFailedCount); + (void)LosBufPrintf(seqBuf, "shm size: %u\n", newIPCLimit->shmSize); + (void)LosBufPrintf(seqBuf, "shm failed count: %u\n", newIPCLimit->shmFailedCount); + (void)LOS_MemFree(m_aucSysMem1, newIPCLimit); + return 0; +} +#endif + +#ifdef LOSCFG_KERNEL_DEV_PLIMIT +static ssize_t DevLimitWriteAllow(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + char *kbuf = NULL; + + if ((pf == NULL) || (pf->pPDE == NULL) || (buf == NULL) || (count <= 0)) { + return -EINVAL; + } + + unsigned ret = MemUserCopy(buf, count, &kbuf); + if (ret != 0) { + return -ret; + } else if ((ret == 0) && (kbuf != NULL)) { + buf = (const char *)kbuf; + } + + ProcLimiterSet *plimit = (ProcLimiterSet *)pf->pPDE->data; + ret = OsDevLimitWriteAllow(plimit, buf, count); + (VOID)LOS_MemFree(m_aucSysMem1, kbuf); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t DevLimitWriteDeny(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + char *kbuf = NULL; + + if ((pf == NULL) || (pf->pPDE == NULL) || (buf == NULL) || (count <= 0)) { + return -EINVAL; + } + + unsigned ret = MemUserCopy(buf, count, &kbuf); + if (ret != 0) { + return -ret; + } else if ((ret == 0) && (kbuf != NULL)) { + buf = (const char *)kbuf; + } + + ProcLimiterSet *plimit = (ProcLimiterSet *)pf->pPDE->data; + ret = OsDevLimitWriteDeny(plimit, buf, count); + (VOID)LOS_MemFree(m_aucSysMem1, kbuf); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t DevLimitShow(struct SeqBuf *seqBuf, VOID *data) +{ + ProcDevLimit *devLimit = (ProcDevLimit *)data; + if ((seqBuf == NULL) || (devLimit == NULL)) { + return -EINVAL; + } + + unsigned ret = OsDevLimitShow(devLimit, seqBuf); + if (ret != LOS_OK) { + return -ret; + } + return 0; +} +#endif + +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT +static ssize_t SchedLimitReadPeriod(struct SeqBuf *seqBuf, VOID *data) +{ + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)data; + if ((seqBuf == NULL) || (schedLimit == NULL)) { + return -EINVAL; + } + + (void)LosBufPrintf(seqBuf, "%lld\n", schedLimit->period); + return 0; +} + +static ssize_t SchedLimitWritePeriod(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + long long int value = GetPidLimitValue(pf, buf, count); + if (value < 0) { + return value; + } + + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)pf->pPDE->data; + unsigned ret = OsSchedLimitSetPeriod(schedLimit, (unsigned long long)value); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +static ssize_t SchedLimitReadQuota(struct SeqBuf *seqBuf, VOID *data) +{ + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)data; + if ((seqBuf == NULL) || (schedLimit == NULL)) { + return -EINVAL; + } + + (void)LosBufPrintf(seqBuf, "%lld\n", schedLimit->quota); + return 0; +} + +static ssize_t SchedLimitWriteQuota(struct ProcFile *pf, const CHAR *buf, size_t count, loff_t *ppos) +{ + (void)ppos; + long long int value = GetPidLimitValue(pf, buf, count); + if (value < 0) { + return value; + } + + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)pf->pPDE->data; + unsigned ret = OsSchedLimitSetQuota(schedLimit, (unsigned long long)value); + if (ret != LOS_OK) { + return -ret; + } + return count; +} + +#define TIME_CYCLE_TO_US(time) ((((UINT64)time) * OS_NS_PER_CYCLE) / OS_SYS_NS_PER_US) +#define SCHED_DEFAULT_VALUE (0x101010101010101) + +static ssize_t SchedLimitShow(struct SeqBuf *seqBuf, VOID *data) +{ + ProcLimiterSet *plimits = (ProcLimiterSet *)data; + if ((seqBuf == NULL) || (plimits == NULL)) { + return -EINVAL; + } + + UINT32 pidMax = LOS_GetSystemProcessMaximum(); + UINT32 size = pidMax * sizeof(unsigned long long); + unsigned long long *usage = (unsigned long long *)LOS_MemAlloc(m_aucSysMem1, size); + if (usage == NULL) { + return -ENOMEM; + } + (void)memset_s(usage, size, 1, size); + + unsigned int ret = OsPLimitsSchedUsageGet(plimits, usage, size); + if (ret != LOS_OK) { + (VOID)LOS_MemFree(m_aucSysMem1, usage); + return -ret; + } + + for (unsigned int index = 0; index < pidMax; index++) { + if (usage[index] == SCHED_DEFAULT_VALUE) { + continue; + } + (void)LosBufPrintf(seqBuf, "PID: %u runTime: %llu us\n", index, TIME_CYCLE_TO_US(usage[index])); + } + (void)LOS_MemFree(m_aucSysMem1, usage); + return 0; +} +#endif + +#define PROC_PLIMITS_MODE (S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +void ProcLimitsInit(void) +{ + struct ProcDirEntry *parentPDE = CreateProcEntry("plimits", PROC_PLIMITS_MODE, NULL); + if (parentPDE == NULL) { + return; + } + ProcLimiterSet *plimits = OsRootPLimitsGet(); + parentPDE->procDirOps = &g_procDirOperations; + parentPDE->data = (VOID *)plimits; + parentPDE->dataType = PROC_DATA_STATIC; + plimits->mask = BIT(PROCESS_LIMITER_ID_PIDS) | BIT(PROCESS_LIMITER_COUNT); +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + plimits->mask |= BIT(PROCESS_LIMITER_ID_MEM); +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + plimits->mask |= BIT(PROCESS_LIMITER_ID_IPC); +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT + plimits->mask |= BIT(PROCESS_LIMITER_ID_DEV); +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + plimits->mask |= BIT(PROCESS_LIMITER_ID_SCHED); +#endif + ProcLimiterDirEntryInit(parentPDE, plimits->mask, PLIMIT_FILE_MODE_MASK_WRITE); + return; +} +#endif diff --git a/fs/proc/os_adapt/proc_init.c b/fs/proc/os_adapt/proc_init.c index 3a5faeb4313d8f905e77b6ea7a83aa17f22226f4..b6cb4386dcb72fd23b3d0163083d45ac13f7a914 100644 --- a/fs/proc/os_adapt/proc_init.c +++ b/fs/proc/os_adapt/proc_init.c @@ -72,6 +72,9 @@ void ProcFsInit(void) ProcSysMemInfoInit(); ProcFileSysInit(); #endif +#ifdef LOSCFG_KERNEL_PLIMITS + ProcLimitsInit(); +#endif } LOS_MODULE_INIT(ProcFsInit, LOS_INIT_LEVEL_KMOD_EXTENDED); diff --git a/fs/proc/os_adapt/proc_vfs.c b/fs/proc/os_adapt/proc_vfs.c index 9bce387abf9d83f4ad521976398feb266b802d43..b479bd6394f9b02a9a615a58113b6f21494409f2 100644 --- a/fs/proc/os_adapt/proc_vfs.c +++ b/fs/proc/os_adapt/proc_vfs.c @@ -239,6 +239,53 @@ int VfsProcfsStat(struct Vnode *node, struct stat *buf) return LOS_OK; } +#ifdef LOSCFG_KERNEL_PLIMITS +int VfsProcfsMkdir(struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode) +{ + struct ProcDirEntry *parentEntry = VnodeToEntry(parent); + struct ProcDirEntry *pde = NULL; + if ((parentEntry->procDirOps == NULL) || (parentEntry->procDirOps->mkdir == NULL)) { + return -ENOSYS; + } + + int ret = parentEntry->procDirOps->mkdir(parentEntry, dirName, mode, &pde); + if ((ret < 0) || (pde == NULL)) { + return ret; + } + + *vnode = EntryToVnode(pde); + (*vnode)->vop = parent->vop; + (*vnode)->parent = parent; + (*vnode)->originMount = parent->originMount; + if ((*vnode)->type == VNODE_TYPE_DIR) { + (*vnode)->mode = S_IFDIR | PROCFS_DEFAULT_MODE; + } else { + (*vnode)->mode = S_IFREG | PROCFS_DEFAULT_MODE; + } + return ret; +} + +int VfsProcfsRmdir(struct Vnode *parent, struct Vnode *vnode, const char *dirName) +{ + if (parent == NULL) { + return -EINVAL; + } + + struct ProcDirEntry *parentEntry = VnodeToEntry(parent); + if ((parentEntry->procDirOps == NULL) || (parentEntry->procDirOps->rmdir == NULL)) { + return -ENOSYS; + } + + struct ProcDirEntry *dirEntry = VnodeToEntry(vnode); + int ret = parentEntry->procDirOps->rmdir(parentEntry, dirEntry, dirName); + if (ret < 0) { + return ret; + } + vnode->data = NULL; + return 0; +} +#endif + int VfsProcfsReaddir(struct Vnode *node, struct fs_dirent_s *dir) { int result; @@ -350,7 +397,7 @@ int VfsProcfsClose(struct file *filep) VnodeHold(); struct Vnode *node = filep->f_vnode; struct ProcDirEntry *pde = VnodeToEntry(node); - if (pde == NULL) { + if ((pde == NULL) || (pde->pf == NULL)) { VnodeDrop(); return -EPERM; } @@ -410,6 +457,10 @@ static struct VnodeOps g_procfsVops = { .Closedir = VfsProcfsClosedir, .Truncate = VfsProcfsTruncate, .Readlink = VfsProcfsReadlink, +#ifdef LOSCFG_KERNEL_PLIMITS + .Mkdir = VfsProcfsMkdir, + .Rmdir = VfsProcfsRmdir, +#endif }; static struct file_operations_vfs g_procfsFops = { diff --git a/fs/proc/os_adapt/process_proc.c b/fs/proc/os_adapt/process_proc.c index 9adfa6b3e63ae1e50349d5e37e219fb64f195511..fcf9673c15d66490fde5796cb2ffca3d9e166c3e 100644 --- a/fs/proc/os_adapt/process_proc.c +++ b/fs/proc/os_adapt/process_proc.c @@ -588,6 +588,7 @@ void ProcFreeProcessDir(struct ProcDirEntry *processDir) static struct ProcDirEntry *ProcCreatePorcess(UINT32 pid, struct ProcProcess *porcess, uintptr_t processCB) { int ret; + struct ProcDataParm dataParm; char pidName[PROC_PID_DIR_LEN] = {0}; struct ProcessData *data = (struct ProcessData *)malloc(sizeof(struct ProcessData)); if (data == NULL) { @@ -613,7 +614,9 @@ static struct ProcDirEntry *ProcCreatePorcess(UINT32 pid, struct ProcProcess *po data->process = processCB; data->type = porcess->type; - struct ProcDirEntry *container = ProcCreateData(pidName, porcess->mode, NULL, porcess->fileOps, (void *)data); + dataParm.data = data; + dataParm.dataType = PROC_DATA_FREE; + struct ProcDirEntry *container = ProcCreateData(pidName, porcess->mode, NULL, porcess->fileOps, &dataParm); if (container == NULL) { free(data); PRINT_ERR("create /proc/%s error!\n", pidName); diff --git a/fs/proc/src/proc_file.c b/fs/proc/src/proc_file.c index 5a87a4e09fa0a6b484e84ddcd712c06858048532..879d4507430fdb71e5276c223d2ac772c615f731 100644 --- a/fs/proc/src/proc_file.c +++ b/fs/proc/src/proc_file.c @@ -296,7 +296,7 @@ static int ProcAddNode(struct ProcDirEntry *parent, struct ProcDirEntry *pn) return 0; } -static void ProcDetachNode(struct ProcDirEntry *pn) +void ProcDetachNode(struct ProcDirEntry *pn) { struct ProcDirEntry *parent = pn->parent; struct ProcDirEntry **iter = NULL; @@ -379,7 +379,7 @@ struct ProcDirEntry *CreateProcEntry(const char *name, mode_t mode, struct ProcD return pde; } -static void ProcEntryClearVnode(struct ProcDirEntry *entry) +void ProcEntryClearVnode(struct ProcDirEntry *entry) { struct Vnode *item = NULL; struct Vnode *nextItem = NULL; @@ -404,16 +404,14 @@ static void FreeProcEntry(struct ProcDirEntry *entry) return; } - ProcEntryClearVnode(entry); - if (entry->pf != NULL) { free(entry->pf); entry->pf = NULL; } - if (entry->data != NULL) { + if ((entry->dataType == PROC_DATA_FREE) && (entry->data != NULL)) { free(entry->data); - entry->data = NULL; } + entry->data = NULL; free(entry); } @@ -424,7 +422,7 @@ void ProcFreeEntry(struct ProcDirEntry *pn) } } -static void RemoveProcEntryTravalsal(struct ProcDirEntry *pn) +void RemoveProcEntryTravalsal(struct ProcDirEntry *pn) { if (pn == NULL) { return; @@ -432,6 +430,8 @@ static void RemoveProcEntryTravalsal(struct ProcDirEntry *pn) RemoveProcEntryTravalsal(pn->next); RemoveProcEntryTravalsal(pn->subdir); + ProcEntryClearVnode(pn); + ProcFreeEntry(pn); } @@ -461,6 +461,9 @@ void RemoveProcEntry(const char *name, struct ProcDirEntry *parent) spin_unlock(&procfsLock); RemoveProcEntryTravalsal(pn->subdir); + + ProcEntryClearVnode(pn); + ProcFreeEntry(pn); } @@ -475,14 +478,17 @@ struct ProcDirEntry *ProcMkdir(const char *name, struct ProcDirEntry *parent) } struct ProcDirEntry *ProcCreateData(const char *name, mode_t mode, struct ProcDirEntry *parent, - const struct ProcFileOperations *procFileOps, void *data) + const struct ProcFileOperations *procFileOps, struct ProcDataParm *param) { struct ProcDirEntry *pde = CreateProcEntry(name, mode, parent); if (pde != NULL) { if (procFileOps != NULL) { pde->procFileOps = procFileOps; } - pde->data = data; + if (param != NULL) { + pde->data = param->data; + pde->dataType = param->dataType; + } } return pde; } @@ -639,12 +645,15 @@ int WriteProcFile(struct ProcDirEntry *pde, const void *buf, size_t len) return -EISDIR; } +#ifndef LOSCFG_KERNEL_PLIMITS spin_lock(&procfsLock); +#endif if ((pde->procFileOps != NULL) && (pde->procFileOps->write != NULL)) { result = pde->procFileOps->write(pde->pf, (const char *)buf, len, &(pde->pf->fPos)); } +#ifndef LOSCFG_KERNEL_PLIMITS spin_unlock(&procfsLock); - +#endif return result; } diff --git a/kernel/base/container/los_pid_container.c b/kernel/base/container/los_pid_container.c index 2fe6dcbc3a5d3090bf2a016b8500003cc266e489..a90ca7903f236113e948b9538c67dde4f8273018 100644 --- a/kernel/base/container/los_pid_container.c +++ b/kernel/base/container/los_pid_container.c @@ -214,7 +214,7 @@ VOID OsPidContainerDestroyAllProcess(LosProcessCB *curr) for (UINT32 index = 2; index < LOSCFG_BASE_CORE_PROCESS_LIMIT; index++) { /* 2: ordinary process */ SCHEDULER_LOCK(intSave); LosProcessCB *processCB = OS_PCB_FROM_PID(index); - if (OsProcessIsUnused(processCB)) { + if (OsProcessIsUnused(processCB) || (processCB->parentProcess == NULL)) { SCHEDULER_UNLOCK(intSave); continue; } diff --git a/kernel/base/core/los_process.c b/kernel/base/core/los_process.c index cddf2b51738567f3ee7646097af488e0c03015c8..9b1942d41e538e6362484f8876253e60f4d39bbd 100644 --- a/kernel/base/core/los_process.c +++ b/kernel/base/core/los_process.c @@ -451,7 +451,9 @@ LITE_OS_SEC_TEXT VOID OsProcessResourcesToFree(LosProcessCB *processCB) } processCB->files = NULL; #endif - +#ifdef LOSCFG_KERNEL_PLIMITS + OsPLimitsDeleteProcess(processCB); +#endif if (processCB->resourceLimit != NULL) { (VOID)LOS_MemFree((VOID *)m_aucSysMem0, processCB->resourceLimit); processCB->resourceLimit = NULL; @@ -606,7 +608,9 @@ UINT32 OsProcessInit(VOID) #ifdef LOSCFG_KERNEL_CONTAINER OsInitRootContainer(); #endif - +#ifdef LOSCFG_KERNEL_PLIMITS + OsProcLimiterSetInit(); +#endif SystemProcessEarlyInit(OsGetIdleProcess()); SystemProcessEarlyInit(OsGetUserInitProcess()); SystemProcessEarlyInit(OsGetKernelInitProcess()); @@ -883,6 +887,13 @@ STATIC UINT32 OsSystemProcessInit(LosProcessCB *processCB, UINT32 flags, const C } #endif +#ifdef LOSCFG_KERNEL_PLIMITS + ret = OsPLimitsAddProcess(NULL, processCB); + if (ret != LOS_OK) { + ret = LOS_ENOMEM; + goto EXIT; + } +#endif return LOS_OK; EXIT: @@ -2066,6 +2077,13 @@ STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 si if (ret != LOS_OK) { goto ERROR_INIT; } + +#ifdef LOSCFG_KERNEL_PLIMITS + ret = OsPLimitsAddProcess(run->plimits, child); + if (ret != LOS_OK) { + goto ERROR_INIT; + } +#endif #endif ret = OsForkInitPCB(flags, child, name, sp, size); diff --git a/kernel/base/include/los_process_pri.h b/kernel/base/include/los_process_pri.h index a75836a6220e24178351757f2a5f124b5e41475b..1fa5acbb5cffde54bbbe76d4537a090b58e666c6 100644 --- a/kernel/base/include/los_process_pri.h +++ b/kernel/base/include/los_process_pri.h @@ -50,6 +50,9 @@ #ifdef LOSCFG_KERNEL_CONTAINER #include "los_container_pri.h" #endif +#ifdef LOSCFG_KERNEL_PLIMITS +#include "los_plimits.h" +#endif #ifdef __cplusplus #if __cplusplus @@ -139,6 +142,11 @@ typedef struct ProcessCB { #ifdef LOSCFG_PROC_PROCESS_DIR struct ProcDirEntry *procDir; #endif +#ifdef LOSCFG_KERNEL_PLIMITS + ProcLimiterSet *plimits; + LOS_DL_LIST plimitsList; /* plimit process list */ + PLimitsData limitStat; +#endif } LosProcessCB; extern LosProcessCB *g_processCBArray; diff --git a/kernel/base/include/los_sched_pri.h b/kernel/base/include/los_sched_pri.h index b17fd729b0e1a6f3688b6eac552eef904ab2c955..1eae0a62fe63548aec9c3e0ec51785f63df6781a 100644 --- a/kernel/base/include/los_sched_pri.h +++ b/kernel/base/include/los_sched_pri.h @@ -429,7 +429,7 @@ typedef struct TagTaskCB { PidContainer *pidContainer; #endif #ifdef LOSCFG_IPC_CONTAINER - BOOL cloneIpc; + BOOL cloneIpc; #endif } LosTaskCB; @@ -619,6 +619,10 @@ STATIC INLINE VOID SchedTaskUnfreeze(LosTaskCB *taskCB) g_taskScheduled &= ~(1U << (cpuid)); \ } while (0); +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT +BOOL OsSchedLimitCheckTime(LosTaskCB *task); +#endif + STATIC INLINE LosTaskCB *HPFRunqueueTopTaskGet(HPFRunqueue *rq) { LosTaskCB *newTask = NULL; @@ -634,6 +638,12 @@ STATIC INLINE LosTaskCB *HPFRunqueueTopTaskGet(HPFRunqueue *rq) while (bitmap) { UINT32 priority = CLZ(bitmap); LOS_DL_LIST_FOR_EACH_ENTRY(newTask, &queueList->priQueList[priority], LosTaskCB, pendList) { +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + if (!OsSchedLimitCheckTime(newTask)) { + bitmap &= ~(1U << (OS_PRIORITY_QUEUE_NUM - priority - 1)); + continue; + } +#endif #ifdef LOSCFG_KERNEL_SMP if (newTask->cpuAffiMask & (1U << cpuid)) { #endif diff --git a/kernel/base/include/los_task_pri.h b/kernel/base/include/los_task_pri.h index e056ffb7fa485a7404ae53f53ea7cc6a0404b84e..fd487a0c1f0280d54e3c7398b28b8e67f51077e5 100644 --- a/kernel/base/include/los_task_pri.h +++ b/kernel/base/include/los_task_pri.h @@ -54,6 +54,7 @@ extern "C" { /* scheduler lock */ extern SPIN_LOCK_S g_taskSpin; +#define SCHEDULER_HELD() LOS_SpinHeld(&g_taskSpin) #define SCHEDULER_LOCK(state) LOS_SpinLockSave(&g_taskSpin, &(state)) #define SCHEDULER_UNLOCK(state) LOS_SpinUnlockRestore(&g_taskSpin, state) diff --git a/kernel/base/sched/los_priority.c b/kernel/base/sched/los_priority.c index c667668afff950b477136140f533a1cb1ee31ace..e0db64f27d39b0bec1be4f809c8da0fc5dd89c4f 100644 --- a/kernel/base/sched/los_priority.c +++ b/kernel/base/sched/los_priority.c @@ -98,6 +98,9 @@ STATIC VOID HPFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 curr taskCB->schedStat.timeSliceRealTime += incTime; #endif } +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + OsSchedLimitUpdateRuntime(taskCB, currTime, incTime); +#endif taskCB->irqUsedTime = 0; taskCB->startTime = currTime; if (taskCB->timeSlice <= OS_TIME_SLICE_MIN) { diff --git a/kernel/base/vm/los_vm_fault.c b/kernel/base/vm/los_vm_fault.c index 47eab9d7ad3a92106d81ded80f6812a43163e328..86b081999bda198d41faeb7dae8f37f7c57113d7 100644 --- a/kernel/base/vm/los_vm_fault.c +++ b/kernel/base/vm/los_vm_fault.c @@ -359,6 +359,12 @@ STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame) return LOS_ERRNO_VM_ACCESS_DENIED; } +#ifdef LOSCFG_KERNEL_PLIMITS + if (OsMemLimitCheckAndMemAdd(PAGE_SIZE) != LOS_OK) { + return LOS_ERRNO_VM_NO_MEMORY; + } +#endif + (VOID)LOS_MuxAcquire(&space->regionMux); region = LOS_RegionFind(space, vaddr); if (region == NULL) { @@ -450,6 +456,9 @@ VMM_MAP_FAILED: } CHECK_FAILED: OsFaultTryFixup(frame, excVaddr, &status); +#ifdef LOSCFG_KERNEL_PLIMITS + OsMemLimitMemFree(PAGE_SIZE); +#endif DONE: (VOID)LOS_MuxRelease(&space->regionMux); return status; diff --git a/kernel/base/vm/los_vm_page.c b/kernel/base/vm/los_vm_page.c index 04ac1801c93e98887f77f9e6e9abde332beee1d7..650fd0b01978c1315be6223592ab0f04e969da26 100644 --- a/kernel/base/vm/los_vm_page.c +++ b/kernel/base/vm/los_vm_page.c @@ -34,7 +34,9 @@ #include "los_vm_phys.h" #include "los_vm_boot.h" #include "los_vm_filemap.h" - +#ifdef LOSCFG_KERNEL_MEM_PLIMIT +#include "los_plimits.h" +#endif #ifdef LOSCFG_KERNEL_VM @@ -81,7 +83,8 @@ VOID OsVmPageStartup(VOID) * struct LosVmPage occupied, which satisfies the equation: * nPage * sizeof(LosVmPage) + nPage * PAGE_SIZE = OsVmPhysPageNumGet() * PAGE_SIZE. */ - nPage = OsVmPhysPageNumGet() * PAGE_SIZE / (sizeof(LosVmPage) + PAGE_SIZE); + UINT32 pageNum = OsVmPhysPageNumGet(); + nPage = pageNum * PAGE_SIZE / (sizeof(LosVmPage) + PAGE_SIZE); g_vmPageArraySize = nPage * sizeof(LosVmPage); g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize); @@ -89,6 +92,9 @@ VOID OsVmPageStartup(VOID) OsVmPhysSegAdd(); OsVmPhysInit(); +#ifdef LOSCFG_KERNEL_PLIMITS + OsMemLimitSetLimit(pageNum * PAGE_SIZE); +#endif for (segID = 0; segID < g_vmPhysSegNum; segID++) { seg = &g_vmPhysSeg[segID]; diff --git a/kernel/base/vm/los_vm_phys.c b/kernel/base/vm/los_vm_phys.c index c051bd1a6efb4d7d676d4aa98e646b77f519017f..30fb2f4bc0dbb16e8ffc430e467c176d6d0f44de 100644 --- a/kernel/base/vm/los_vm_phys.c +++ b/kernel/base/vm/los_vm_phys.c @@ -456,6 +456,9 @@ VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages) OsVmPhysPagesFreeContiguous(page, nPages); LOS_SpinUnlockRestore(&seg->freeListLock, intSave); +#ifdef LOSCFG_KERNEL_PLIMITS + OsMemLimitMemFree(nPages * PAGE_SIZE); +#endif } PADDR_T OsKVaddrToPaddr(VADDR_T kvaddr) @@ -503,6 +506,9 @@ VOID LOS_PhysPageFree(LosVmPage *page) LOS_SpinUnlockRestore(&seg->freeListLock, intSave); } +#ifdef LOSCFG_KERNEL_PLIMITS + OsMemLimitMemFree(PAGE_SIZE); +#endif } LosVmPage *LOS_PhysPageAlloc(VOID) diff --git a/kernel/base/vm/shm.c b/kernel/base/vm/shm.c index 5a9d5965497848c45f382f64bd34f3e37792a688..9f3f878d1bdfe6a839511ce1a4243cb16fe8d86b 100644 --- a/kernel/base/vm/shm.c +++ b/kernel/base/vm/shm.c @@ -193,40 +193,58 @@ STATIC VOID ShmPagesRefDec(struct shmIDSource *seg) } } -STATIC INT32 ShmAllocSeg(key_t key, size_t size, INT32 shmflg) +STATIC INT32 ShmAllocSegCheck(key_t key, size_t *size, INT32 *segNum) { INT32 i; - INT32 segNum = -1; - struct shmIDSource *seg = NULL; - size_t count; - - if ((size == 0) || (size < IPC_SHM_INFO.shmmin) || - (size > IPC_SHM_INFO.shmmax)) { + if ((*size == 0) || (*size < IPC_SHM_INFO.shmmin) || + (*size > IPC_SHM_INFO.shmmax)) { return -EINVAL; } - size = LOS_Align(size, PAGE_SIZE); - if ((IPC_SHM_USED_PAGE_COUNT + (size >> PAGE_SHIFT)) > IPC_SHM_INFO.shmall) { + *size = LOS_Align(*size, PAGE_SIZE); + if ((IPC_SHM_USED_PAGE_COUNT + (*size >> PAGE_SHIFT)) > IPC_SHM_INFO.shmall) { return -ENOMEM; } for (i = 0; i < IPC_SHM_INFO.shmmni; i++) { if (IPC_SHM_SEGS[i].status & SHM_SEG_FREE) { IPC_SHM_SEGS[i].status &= ~SHM_SEG_FREE; - segNum = i; + *segNum = i; break; } } - if (segNum < 0) { + if (*segNum < 0) { return -ENOSPC; } +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + if (OsIPCLimitShmAlloc(*size) != LOS_OK) { + return -ENOMEM; + } +#endif + return 0; +} + +STATIC INT32 ShmAllocSeg(key_t key, size_t size, INT32 shmflg) +{ + INT32 segNum = -1; + struct shmIDSource *seg = NULL; + size_t count; + + INT32 ret = ShmAllocSegCheck(key, &size, &segNum); + if (ret < 0) { + return ret; + } + seg = &IPC_SHM_SEGS[segNum]; count = LOS_PhysPagesAlloc(size >> PAGE_SHIFT, &seg->node); if (count != (size >> PAGE_SHIFT)) { (VOID)LOS_PhysPagesFree(&seg->node); seg->status = SHM_SEG_FREE; +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + OsIPCLimitShmFree(size); +#endif return -ENOMEM; } @@ -264,6 +282,9 @@ STATIC INLINE VOID ShmFreeSeg(struct shmIDSource *seg, UINT32 *shmUsedPageCount) VM_ERR("free physical pages failed, count = %d, size = %d", count, seg->ds.shm_segsz >> PAGE_SHIFT); return; } +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + OsIPCLimitShmFree(seg->ds.shm_segsz); +#endif if (shmUsedPageCount != NULL) { (*shmUsedPageCount) -= seg->ds.shm_segsz >> PAGE_SHIFT; } diff --git a/kernel/extended/BUILD.gn b/kernel/extended/BUILD.gn index 0ddf48048fa29651a258f340aae71ce8566d15a9..6bada0f1056ab64fc2753ed158574f2c19b8e67d 100644 --- a/kernel/extended/BUILD.gn +++ b/kernel/extended/BUILD.gn @@ -42,6 +42,7 @@ group("extended") { "lms", "perf", "pipes", + "plimit", "power", "trace", "vdso", @@ -62,5 +63,6 @@ config("public") { "perf:public", "lms:public", "power:public", + "plimit:public", ] } diff --git a/kernel/extended/Kconfig b/kernel/extended/Kconfig index abb7bec3f20030c255fbd6b1f695dc36dc918276..45dababf29659bbccb0987e7284d594c862a4f08 100644 --- a/kernel/extended/Kconfig +++ b/kernel/extended/Kconfig @@ -76,6 +76,31 @@ config KERNEL_PIPE help Answer Y to enable LiteOS support pipes. +config KERNEL_PLIMITS + bool "Enable plimits Feature" + default n + depends on KERNEL_EXTKERNEL + +config KERNEL_MEM_PLIMIT + bool "Enable mem limits Feature" + default n + depends on KERNEL_PLIMITS + +config KERNEL_IPC_PLIMIT + bool "Enable ipc limits Feature" + default n + depends on KERNEL_PLIMITS + +config KERNEL_DEV_PLIMIT + bool "Enable dev limits Feature" + default n + depends on KERNEL_PLIMITS + +config KERNEL_SCHED_PLIMIT + bool "Enable sched limits Feature" + default n + depends on KERNEL_PLIMITS + config BASE_CORE_HILOG bool "Enable Hilog" default y @@ -104,4 +129,4 @@ source "kernel/extended/perf/Kconfig" source "kernel/extended/lms/Kconfig" ######################### config options of hilog ######################### -source "kernel/extended/hilog/Kconfig" \ No newline at end of file +source "kernel/extended/hilog/Kconfig" diff --git a/kernel/extended/plimit/BUILD.gn b/kernel/extended/plimit/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..8632073c0c99514b38313bf1913d487c8fdc9486 --- /dev/null +++ b/kernel/extended/plimit/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright (c) 2023-2023 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. + +import("//kernel/liteos_a/liteos.gni") + +module_switch = true +module_name = get_path_info(rebase_path("."), "name") +kernel_module(module_name) { + sources = [ + "los_devicelimit.c", + "los_ipclimit.c", + "los_memlimit.c", + "los_plimits.c", + "los_processlimit.c", + "los_schedlimit.c", + ] +} + +config("public") { + include_dirs = [ "." ] +} diff --git a/kernel/extended/plimit/Makefile b/kernel/extended/plimit/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c2f9209e65dae79db2febdfa26872a161c302640 --- /dev/null +++ b/kernel/extended/plimit/Makefile @@ -0,0 +1,35 @@ +# Copyright (c) 2023-2023 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 $(LITEOSTOPDIR)/config.mk + +MODULE_NAME := $(notdir $(shell pwd)) + +LOCAL_SRCS := $(wildcard *.c) + +include $(MODULE) diff --git a/kernel/extended/plimit/los_devicelimit.c b/kernel/extended/plimit/los_devicelimit.c new file mode 100644 index 0000000000000000000000000000000000000000..eedb4681a45c3c0e7f2aec2760c33a5ce1f3e002 --- /dev/null +++ b/kernel/extended/plimit/los_devicelimit.c @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2023-2023 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 "los_seq_buf.h" +#include "los_bitmap.h" +#include "los_process_pri.h" +#include "los_devicelimit.h" + +#ifdef LOSCFG_KERNEL_DEV_PLIMIT +#define TYPE_CHAR_LEN (1) +#define DEVICE_NAME_PREFIX_SPACE (1) +#define DEVICE_ACCESS_MAXLEN (3) +#define BUF_SEPARATOR (5) + +STATIC ProcDevLimit *g_procDevLimit = NULL; + +VOID OsDevLimitInit(UINTPTR limit) +{ + ProcDevLimit *deviceLimit = (ProcDevLimit *)limit; + deviceLimit->behavior = DEVLIMIT_DEFAULT_ALLOW; + LOS_ListInit(&(deviceLimit->accessList)); + g_procDevLimit = deviceLimit; +} + +VOID *OsDevLimitAlloc(VOID) +{ + ProcDevLimit *plimit = (ProcDevLimit *)LOS_KernelMalloc(sizeof(ProcDevLimit)); + if (plimit == NULL) { + return NULL; + } + (VOID)memset_s(plimit, sizeof(ProcDevLimit), 0, sizeof(ProcDevLimit)); + LOS_ListInit(&(plimit->accessList)); + plimit->behavior = DEVLIMIT_DEFAULT_NONE; + LOS_AtomicSet(&plimit->rc, 1); + return (VOID *)plimit; +} + +STATIC VOID DevAccessListDelete(ProcDevLimit *devLimit) +{ + DevAccessItem *delItem = NULL; + DevAccessItem *tmpItem = NULL; + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(delItem, tmpItem, &devLimit->accessList, DevAccessItem, list) { + LOS_ListDelete(&delItem->list); + LOS_KernelFree((VOID *)delItem); + } +} + +VOID OsDevLimitFree(UINTPTR limit) +{ + ProcDevLimit *devLimit = (ProcDevLimit *)limit; + if (devLimit == NULL) { + return; + } + + LOS_AtomicDec(&devLimit->rc); + if (LOS_AtomicRead(&devLimit->rc) <= 0) { + DevAccessListDelete(devLimit); + LOS_KernelFree(devLimit); + } +} + +STATIC UINT32 DevLimitCopyAccess(ProcDevLimit *devLimitDest, ProcDevLimit *devLimitSrc) +{ + DevAccessItem *tmpItem = NULL; + INT32 itemSize = sizeof(DevAccessItem); + devLimitDest->behavior = devLimitSrc->behavior; + LOS_DL_LIST_FOR_EACH_ENTRY(tmpItem, &devLimitSrc->accessList, DevAccessItem, list) { + DevAccessItem *newItem = (DevAccessItem *)LOS_KernelMalloc(itemSize); + if (newItem == NULL) { + return ENOMEM; + } + (VOID)memcpy_s(newItem, sizeof(DevAccessItem), tmpItem, sizeof(DevAccessItem)); + LOS_ListTailInsert(&devLimitDest->accessList, &newItem->list); + } + return LOS_OK; +} + +VOID OsDevLimitCopy(UINTPTR dest, UINTPTR src) +{ + ProcDevLimit *devLimitDest = (ProcDevLimit *)dest; + ProcDevLimit *devLimitSrc = (ProcDevLimit *)src; + (VOID)DevLimitCopyAccess(devLimitDest, devLimitSrc); + devLimitDest->parent = (ProcDevLimit *)src; +} + +VOID OsDevLimitMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process) +{ + (VOID)currLimit; + ProcDevLimit *parentDevLimit = (ProcDevLimit *)parentLimit; + LosProcessCB *pcb = (LosProcessCB *)process; + if (pcb == NULL) { + LOS_AtomicInc(&parentDevLimit->rc); + } +} + +STATIC INLINE INT32 IsSpace(INT32 c) +{ + return (c == ' ' || (unsigned)c - '\t' < BUF_SEPARATOR); +} + +STATIC UINT32 ParseItemAccess(const CHAR *buf, DevAccessItem *item) +{ + switch (*buf) { + case 'a': + item->type = DEVLIMIT_DEV_ALL; + return LOS_OK; + case 'b': + item->type = DEVLIMIT_DEV_BLOCK; + break; + case 'c': + item->type = DEVLIMIT_DEV_CHAR; + break; + default: + return EINVAL; + } + buf += DEVICE_NAME_PREFIX_SPACE; + if (!IsSpace(*buf)) { + return EINVAL; + } + buf += DEVICE_NAME_PREFIX_SPACE; + + for (INT32 count = 0; count < sizeof(item->name) - 1; count++) { + if (IsSpace(*buf)) { + break; + } + item->name[count] = *buf; + buf += TYPE_CHAR_LEN; + } + if (!IsSpace(*buf)) { + return EINVAL; + } + + buf += DEVICE_NAME_PREFIX_SPACE; + for (INT32 i = 0; i < DEVICE_ACCESS_MAXLEN; i++) { + switch (*buf) { + case 'r': + item->access |= DEVLIMIT_ACC_READ; + break; + case 'w': + item->access |= DEVLIMIT_ACC_WRITE; + break; + case 'm': + item->access |= DEVLIMIT_ACC_MKNOD; + break; + case '\n': + case '\0': + i = DEVICE_ACCESS_MAXLEN; + break; + default: + return EINVAL; + } + buf += TYPE_CHAR_LEN; + } + return LOS_OK; +} + +STATIC BOOL DevLimitMayAllowAll(ProcDevLimit *parent) +{ + if (parent == NULL) { + return TRUE; + } + return (parent->behavior == DEVLIMIT_DEFAULT_ALLOW); +} + +STATIC BOOL DevLimitHasChildren(ProcLimitSet *procLimitSet, ProcDevLimit *devLimit) +{ + ProcLimitSet *parent = procLimitSet; + ProcLimitSet *childProcLimitSet = NULL; + if (devLimit == NULL) { + return FALSE; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(childProcLimitSet, &(procLimitSet->childList), ProcLimitSet, childList) { + if (childProcLimitSet == NULL) { + continue; + } + if (childProcLimitSet->parent != parent) { + continue; + } + if (!((childProcLimitSet->mask) & BIT(PROCESS_LIMITER_ID_DEV))) { + continue; + } + return TRUE; + } + return FALSE; +} + +STATIC UINT32 DealItemAllAccess(ProcLimitSet *procLimitSet, ProcDevLimit *devLimit, + ProcDevLimit *devParentLimit, INT32 filetype) +{ + switch (filetype) { + case DEVLIMIT_ALLOW: { + if (DevLimitHasChildren(procLimitSet, devLimit)) { + return EINVAL; + } + if (!DevLimitMayAllowAll(devParentLimit)) { + return EPERM; + } + DevAccessListDelete(devLimit); + devLimit->behavior = DEVLIMIT_DEFAULT_ALLOW; + if (devParentLimit == NULL) { + break; + } + DevLimitCopyAccess(devLimit, devParentLimit); + break; + } + case DEVLIMIT_DENY: { + if (DevLimitHasChildren(procLimitSet, devLimit)) { + return EINVAL; + } + DevAccessListDelete(devLimit); + devLimit->behavior = DEVLIMIT_DEFAULT_DENY; + break; + } + default: + return EINVAL; + } + return LOS_OK; +} + +STATIC BOOL DevLimitMatchItemPartial(LOS_DL_LIST *list, DevAccessItem *item) +{ + if ((list == NULL) || (item == NULL)) { + return FALSE; + } + if (LOS_ListEmpty(list)) { + return FALSE; + } + DevAccessItem *walk = NULL; + LOS_DL_LIST_FOR_EACH_ENTRY(walk, list, DevAccessItem, list) { + if (item->type != walk->type) { + continue; + } + if ((strcmp(walk->name, "*") != 0) && (strcmp(item->name, "*") != 0) + && (strcmp(walk->name, item->name) != 0)) { + continue; + } + if (!(item->access & ~(walk->access))) { + return TRUE; + } + } + return FALSE; +} + +STATIC BOOL DevLimitParentAllowsRmItem(ProcDevLimit *devParentLimit, DevAccessItem *item) +{ + if (devParentLimit == NULL) { + return TRUE; + } + /* Make sure you're not removing part or a whole item existing in the parent plimits */ + return !DevLimitMatchItemPartial(&devParentLimit->accessList, item); +} + +STATIC BOOL DevLimitMatchItem(LOS_DL_LIST *list, DevAccessItem *item) +{ + if ((list == NULL) || (item == NULL)) { + return FALSE; + } + if (LOS_ListEmpty(list)) { + return FALSE; + } + DevAccessItem *walk = NULL; + LOS_DL_LIST_FOR_EACH_ENTRY(walk, list, DevAccessItem, list) { + if (item->type != walk->type) { + continue; + } + if ((strcmp(walk->name, "*") != 0) && (strcmp(walk->name, item->name) != 0)) { + continue; + } + if (!(item->access & ~(walk->access))) { + return TRUE; + } + } + return FALSE; +} + +/** + * This is used to make sure a child plimits won't have more privileges than its parent + */ +STATIC BOOL DevLimitVerifyNewItem(ProcDevLimit *parent, DevAccessItem *item, INT32 currBehavior) +{ + if (parent == NULL) { + return TRUE; + } + + if (parent->behavior == DEVLIMIT_DEFAULT_ALLOW) { + if (currBehavior == DEVLIMIT_DEFAULT_ALLOW) { + return TRUE; + } + return !DevLimitMatchItemPartial(&parent->accessList, item); + } + return DevLimitMatchItem(&parent->accessList, item); +} + +STATIC BOOL DevLimitParentAllowsAddItem(ProcDevLimit *devParentLimit, DevAccessItem *item, INT32 currBehavior) +{ + return DevLimitVerifyNewItem(devParentLimit, item, currBehavior); +} + +STATIC VOID DevLimitAccessListRm(ProcDevLimit *devLimit, DevAccessItem *item) +{ + if ((item == NULL) || (devLimit == NULL)) { + return; + } + DevAccessItem *walk, *tmp = NULL; + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(walk, tmp, &devLimit->accessList, DevAccessItem, list) { + if (walk->type != item->type) { + continue; + } + if (strcmp(walk->name, item->name) != 0) { + continue; + } + walk->access &= ~item->access; + if (!walk->access) { + LOS_ListDelete(&walk->list); + LOS_KernelFree((VOID *)walk); + } + } +} + +STATIC UINT32 DevLimitAccessListAdd(ProcDevLimit *devLimit, DevAccessItem *item) +{ + if ((item == NULL) || (devLimit == NULL)) { + return ENOMEM; + } + + DevAccessItem *walk = NULL; + DevAccessItem *newItem = (DevAccessItem *)LOS_KernelMalloc(sizeof(DevAccessItem)); + if (newItem == NULL) { + return ENOMEM; + } + (VOID)memcpy_s(newItem, sizeof(DevAccessItem), item, sizeof(DevAccessItem)); + LOS_DL_LIST_FOR_EACH_ENTRY(walk, &devLimit->accessList, DevAccessItem, list) { + if (walk->type != item->type) { + continue; + } + if (strcmp(walk->name, item->name) != 0) { + continue; + } + walk->access |= item->access; + LOS_KernelFree((VOID *)newItem); + newItem = NULL; + } + + if (newItem != NULL) { + LOS_ListTailInsert(&devLimit->accessList, &newItem->list); + } + return LOS_OK; +} + +/** + * Revalidate permissions + */ +STATIC VOID DevLimitRevalidateActiveItems(ProcDevLimit *devLimit, ProcDevLimit *devParentLimit) +{ + if ((devLimit == NULL) || (devParentLimit == NULL)) { + return; + } + DevAccessItem *walK = NULL; + DevAccessItem *tmp = NULL; + LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(walK, tmp, &devLimit->accessList, DevAccessItem, list) { + if (!DevLimitParentAllowsAddItem(devParentLimit, walK, devLimit->behavior)) { + DevLimitAccessListRm(devLimit, walK); + } + } +} + +/** + * propagates a new item to the children + */ +STATIC UINT32 DevLimitPropagateItem(ProcLimitSet *procLimitSet, ProcDevLimit *devLimit, DevAccessItem *item) +{ + UINT32 ret = LOS_OK; + ProcLimitSet *parent = procLimitSet; + ProcLimitSet *childProcLimitSet = NULL; + + if ((procLimitSet == NULL) || (item == NULL)) { + return ENOMEM; + } + + if (devLimit == NULL) { + return LOS_OK; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(childProcLimitSet, &procLimitSet->childList, ProcLimitSet, childList) { + if (childProcLimitSet == NULL) { + continue; + } + if (childProcLimitSet->parent != parent) { + continue; + } + if (!((childProcLimitSet->mask) & BIT(PROCESS_LIMITER_ID_DEV))) { + continue; + } + ProcDevLimit *devLimitChild = (ProcDevLimit *)childProcLimitSet->limitsList[PROCESS_LIMITER_ID_DEV]; + if (devLimit->behavior == DEVLIMIT_DEFAULT_ALLOW && + devLimitChild->behavior == DEVLIMIT_DEFAULT_ALLOW) { + ret = DevLimitAccessListAdd(devLimitChild, item); + } else { + DevLimitAccessListRm(devLimitChild, item); + } + DevLimitRevalidateActiveItems(devLimitChild, (ProcDevLimit *)parent->limitsList[PROCESS_LIMITER_ID_DEV]); + } + return ret; +} + +STATIC UINT32 DevLimitUpdateAccess(ProcLimitSet *procLimitSet, const CHAR *buf, INT32 filetype) +{ + UINT32 ret; + UINT32 intSave; + DevAccessItem item = {0}; + + SCHEDULER_LOCK(intSave); + ProcDevLimit *devLimit = (ProcDevLimit *)(procLimitSet->limitsList[PROCESS_LIMITER_ID_DEV]); + ProcDevLimit *devParentLimit = devLimit->parent; + + ret = ParseItemAccess(buf, &item); + if (ret != LOS_OK) { + SCHEDULER_UNLOCK(intSave); + return ret; + } + if (item.type == DEVLIMIT_DEV_ALL) { + ret = DealItemAllAccess(procLimitSet, devLimit, devParentLimit, filetype); + SCHEDULER_UNLOCK(intSave); + return ret; + } + switch (filetype) { + case DEVLIMIT_ALLOW: { + if (devLimit->behavior == DEVLIMIT_DEFAULT_ALLOW) { + if (!DevLimitParentAllowsRmItem(devParentLimit, &item)) { + SCHEDULER_UNLOCK(intSave); + return EPERM; + } + DevLimitAccessListRm(devLimit, &item); + break; + } + if (!DevLimitParentAllowsAddItem(devParentLimit, &item, devLimit->behavior)) { + SCHEDULER_UNLOCK(intSave); + return EPERM; + } + ret = DevLimitAccessListAdd(devLimit, &item); + break; + } + case DEVLIMIT_DENY: { + if (devLimit->behavior == DEVLIMIT_DEFAULT_DENY) { + DevLimitAccessListRm(devLimit, &item); + } else { + ret = DevLimitAccessListAdd(devLimit, &item); + } + // update child access list + ret = DevLimitPropagateItem(procLimitSet, devLimit, &item); + break; + } + default: + ret = EINVAL; + break; + } + SCHEDULER_UNLOCK(intSave); + return ret; +} + + +UINT32 OsDevLimitWriteAllow(ProcLimitSet *plimit, const CHAR *buf, UINT32 size) +{ + (VOID)size; + return DevLimitUpdateAccess(plimit, buf, DEVLIMIT_ALLOW); +} + +UINT32 OsDevLimitWriteDeny(ProcLimitSet *plimit, const CHAR *buf, UINT32 size) +{ + (VOID)size; + return DevLimitUpdateAccess(plimit, buf, DEVLIMIT_DENY); +} + +STATIC VOID DevLimitItemSetAccess(CHAR *acc, INT16 access) +{ + INT32 index = 0; + (VOID)memset_s(acc, ACCLEN, 0, ACCLEN); + if (access & DEVLIMIT_ACC_READ) { + acc[index++] = 'r'; + } + if (access & DEVLIMIT_ACC_WRITE) { + acc[index++] = 'w'; + } + if (access & DEVLIMIT_ACC_MKNOD) { + acc[index++] = 'm'; + } +} + +STATIC CHAR DevLimitItemTypeToChar(INT16 type) +{ + if (type == DEVLIMIT_DEV_ALL) { + return 'a'; + } else if (type == DEVLIMIT_DEV_CHAR) { + return 'c'; + } else if (type == DEVLIMIT_DEV_BLOCK) { + return 'b'; + } + return 'X'; +} + +UINT32 OsDevLimitShow(ProcDevLimit *devLimit, struct SeqBuf *seqBuf) +{ + DevAccessItem *item = NULL; + CHAR acc[ACCLEN]; + UINT32 intSave; + + if ((devLimit == NULL) || (seqBuf == NULL)) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + if (devLimit->behavior == DEVLIMIT_DEFAULT_ALLOW) { + DevLimitItemSetAccess(acc, DEVLIMIT_ACC_MASK); + SCHEDULER_UNLOCK(intSave); + LosBufPrintf(seqBuf, "%c %s %s\n", DevLimitItemTypeToChar(DEVLIMIT_DEV_ALL), "*", acc); + return LOS_OK; + } + LOS_DL_LIST_FOR_EACH_ENTRY(item, &devLimit->accessList, DevAccessItem, list) { + DevLimitItemSetAccess(acc, item->access); + LosBufPrintf(seqBuf, "%c %s %s\n", DevLimitItemTypeToChar(item->type), item->name, acc); + } + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +STATIC INLINE INT16 ConversionDevType(INT32 vnodeType) +{ + INT16 type = 0; + if (vnodeType == VNODE_TYPE_BLK) { + type = DEVLIMIT_DEV_BLOCK; + } else if (vnodeType == VNODE_TYPE_CHR) { + type = DEVLIMIT_DEV_CHAR; + } + return type; +} + +STATIC INLINE INT16 ConversionDevAccess(INT32 flags) +{ + INT16 access = 0; + if ((flags & O_ACCMODE) == O_RDONLY) { + access |= DEVLIMIT_ACC_READ; + } + if (flags & O_WRONLY) { + access |= DEVLIMIT_ACC_WRITE; + } + if (flags & O_RDWR) { + access |= DEVLIMIT_ACC_WRITE | DEVLIMIT_ACC_READ; + } + if (flags & O_CREAT) { + access |= DEVLIMIT_ACC_MKNOD; + } + return access; +} + +UINT32 OsDevLimitCheckPermission(INT32 vnodeType, const CHAR *pathName, INT32 flags) +{ + BOOL matched = FALSE; + DevAccessItem item = {0}; + LosProcessCB *run = OsCurrProcessGet(); + if ((run == NULL) || (run->plimits == NULL)) { + return LOS_OK; + } + + if (pathName == NULL) { + return EINVAL; + } + + ProcDevLimit *devLimit = (ProcDevLimit *)run->plimits->limitsList[PROCESS_LIMITER_ID_DEV]; + + item.type = ConversionDevType(vnodeType); + item.access = ConversionDevAccess(flags); + LOS_ListInit(&(item.list)); + (VOID)strncpy_s(item.name, PATH_MAX, pathName, PATH_MAX); + + if (devLimit->behavior == DEVLIMIT_DEFAULT_ALLOW) { + matched = !DevLimitMatchItemPartial(&devLimit->accessList, &item); + } else { + matched = DevLimitMatchItem(&devLimit->accessList, &item); + } + if (!matched) { + return EPERM; + } + return LOS_OK; +} +#endif diff --git a/kernel/extended/plimit/los_devicelimit.h b/kernel/extended/plimit/los_devicelimit.h new file mode 100644 index 0000000000000000000000000000000000000000..a2310144114fc088f80ed6d6247a33b55809f265 --- /dev/null +++ b/kernel/extended/plimit/los_devicelimit.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023-2023 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. + */ + +#ifndef _LOS_DEVICELIMIT_H +#define _LOS_DEVICELIMIT_H + +#include "los_typedef.h" +#include "los_atomic.h" +#include "los_list.h" +#include "vfs_config.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define DEVLIMIT_ACC_MKNOD 1 +#define DEVLIMIT_ACC_READ 2 +#define DEVLIMIT_ACC_WRITE 4 +#define DEVLIMIT_ACC_MASK (DEVLIMIT_ACC_MKNOD | DEVLIMIT_ACC_READ | DEVLIMIT_ACC_WRITE) + +#define DEVLIMIT_DEV_BLOCK 1 +#define DEVLIMIT_DEV_CHAR 2 +#define DEVLIMIT_DEV_ALL 4 /* all devices */ + +#define DEVLIMIT_ALLOW 1 +#define DEVLIMIT_DENY 2 + +#define ACCLEN 4 + +struct SeqBuf; +typedef struct TagPLimiterSet ProcLimitSet; + +enum DevLimitBehavior { + DEVLIMIT_DEFAULT_NONE, + DEVLIMIT_DEFAULT_ALLOW, + DEVLIMIT_DEFAULT_DENY, +}; + +typedef struct DevAccessItem { + INT16 type; + INT16 access; + LOS_DL_LIST list; + CHAR name[PATH_MAX]; +} DevAccessItem; + +typedef struct ProcDevLimit { + struct ProcDevLimit *parent; + Atomic rc; + UINT8 allowFile; + UINT8 denyFile; + LOS_DL_LIST accessList; // device belong to devicelimite + enum DevLimitBehavior behavior; +} ProcDevLimit; + +VOID OsDevLimitInit(UINTPTR limit); +VOID *OsDevLimitAlloc(VOID); +VOID OsDevLimitFree(UINTPTR limit); +VOID OsDevLimitCopy(UINTPTR dest, UINTPTR src); +VOID OsDevLimitMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process); +UINT32 OsDevLimitWriteAllow(ProcLimitSet *plimit, const CHAR *buf, UINT32 size); +UINT32 OsDevLimitWriteDeny(ProcLimitSet *plimit, const CHAR *buf, UINT32 size); +UINT32 OsDevLimitShow(ProcDevLimit *devLimit, struct SeqBuf *seqBuf); +UINT32 OsDevLimitCheckPermission(INT32 vnodeType, const CHAR *pathName, INT32 flags); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ +#endif /* _LOS_DEVICELIMIT_H */ diff --git a/kernel/extended/plimit/los_ipclimit.c b/kernel/extended/plimit/los_ipclimit.c new file mode 100644 index 0000000000000000000000000000000000000000..c2d6816004a13fe1b3e4197389d563526bddd30e --- /dev/null +++ b/kernel/extended/plimit/los_ipclimit.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2023-2023 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 "los_ipclimit.h" +#include "los_process_pri.h" + +#ifdef LOSCFG_KERNEL_IPC_PLIMIT +STATIC ProcIPCLimit *g_rootIPCLimit = NULL; +#define PLIMIT_IPC_SHM_LIMIT_MAX 104857600 + +VOID OsIPCLimitInit(UINTPTR limite) +{ + ProcIPCLimit *plimite = (ProcIPCLimit *)limite; + plimite->mqCountLimit = LOSCFG_BASE_IPC_QUEUE_LIMIT; + plimite->shmSizeLimit = PLIMIT_IPC_SHM_LIMIT_MAX; + g_rootIPCLimit = plimite; +} + +VOID *OsIPCLimitAlloc(VOID) +{ + ProcIPCLimit *plimite = (ProcIPCLimit *)LOS_KernelMalloc(sizeof(ProcIPCLimit)); + if (plimite == NULL) { + return NULL; + } + (VOID)memset_s(plimite, sizeof(ProcIPCLimit), 0, sizeof(ProcIPCLimit)); + LOS_AtomicSet(&plimite->rc, 1); + return (VOID *)plimite; +} + +VOID OsIPCLimitFree(UINTPTR limite) +{ + ProcIPCLimit *plimite = (ProcIPCLimit *)limite; + if (plimite == NULL) { + return; + } + + LOS_AtomicDec(&plimite->rc); + if (LOS_AtomicRead(&plimite->rc) <= 0) { + LOS_KernelFree((VOID *)plimite); + } +} + +VOID OsIPCLimitCopy(UINTPTR dest, UINTPTR src) +{ + ProcIPCLimit *plimiteDest = (ProcIPCLimit *)dest; + ProcIPCLimit *plimiteSrc = (ProcIPCLimit *)src; + plimiteDest->mqCountLimit = plimiteSrc->mqCountLimit; + plimiteDest->shmSizeLimit = plimiteSrc->shmSizeLimit; + return; +} + +BOOL OsIPCLimiteMigrateCheck(UINTPTR curr, UINTPTR parent) +{ + ProcIPCLimit *currIpcLimit = (ProcIPCLimit *)curr; + ProcIPCLimit *parentIpcLimit = (ProcIPCLimit *)parent; + if ((currIpcLimit->mqCount + parentIpcLimit->mqCount) >= parentIpcLimit->mqCountLimit) { + return FALSE; + } + + if ((currIpcLimit->shmSize + parentIpcLimit->shmSize) >= parentIpcLimit->shmSizeLimit) { + return FALSE; + } + return TRUE; +} + +VOID OsIPCLimitMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process) +{ + ProcIPCLimit *currIpcLimit = (ProcIPCLimit *)currLimit; + ProcIPCLimit *parentIpcLimit = (ProcIPCLimit *)parentLimit; + LosProcessCB *pcb = (LosProcessCB *)process; + + if (pcb == NULL) { + parentIpcLimit->mqCount += currIpcLimit->mqCount; + parentIpcLimit->mqFailedCount += currIpcLimit->mqFailedCount; + parentIpcLimit->shmSize += currIpcLimit->shmSize; + parentIpcLimit->shmFailedCount += currIpcLimit->shmFailedCount; + LOS_AtomicInc(&parentIpcLimit->rc); + return; + } + + parentIpcLimit->mqCount -= pcb->limitStat.mqCount; + parentIpcLimit->shmSize -= pcb->limitStat.shmSize; + currIpcLimit->mqCount += pcb->limitStat.mqCount; + currIpcLimit->shmSize += pcb->limitStat.shmSize; +} + +BOOL OsIPCLimitAddProcessCheck(UINTPTR limit, UINTPTR process) +{ + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)limit; + LosProcessCB *pcb = (LosProcessCB *)process; + if ((ipcLimit->mqCount + pcb->limitStat.mqCount) >= ipcLimit->mqCountLimit) { + return FALSE; + } + + if ((ipcLimit->shmSize + pcb->limitStat.shmSize) >= ipcLimit->shmSizeLimit) { + return FALSE; + } + + return TRUE; +} + +VOID OsIPCLimitAddProcess(UINTPTR limit, UINTPTR process) +{ + LosProcessCB *pcb = (LosProcessCB *)process; + ProcIPCLimit *plimits = (ProcIPCLimit *)limit; + plimits->mqCount += pcb->limitStat.mqCount; + plimits->shmSize += pcb->limitStat.shmSize; + return; +} + +VOID OsIPCLimitDelProcess(UINTPTR limit, UINTPTR process) +{ + LosProcessCB *pcb = (LosProcessCB *)process; + ProcIPCLimit *plimits = (ProcIPCLimit *)limit; + + plimits->mqCount -= pcb->limitStat.mqCount; + plimits->shmSize -= pcb->limitStat.shmSize; + return; +} + +UINT32 OsIPCLimitSetMqLimit(ProcIPCLimit *ipcLimit, UINT32 value) +{ + UINT32 intSave; + + if ((ipcLimit == NULL) || (value == 0) || (value > LOSCFG_BASE_IPC_QUEUE_LIMIT)) { + return EINVAL; + } + + if (ipcLimit == g_rootIPCLimit) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + if (value < ipcLimit->mqCount) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + ipcLimit->mqCountLimit = value; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +UINT32 OsIPCLimitSetShmLimit(ProcIPCLimit *ipcLimit, UINT32 value) +{ + UINT32 intSave; + + if ((ipcLimit == NULL) || (value == 0) || (value > PLIMIT_IPC_SHM_LIMIT_MAX)) { + return EINVAL; + } + + if (ipcLimit == g_rootIPCLimit) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + if (value < ipcLimit->shmSize) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + ipcLimit->shmSizeLimit = value; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +UINT32 OsIPCLimitMqAlloc(VOID) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + LosProcessCB *run = OsCurrProcessGet(); + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)run->plimits->limitsList[PROCESS_LIMITER_ID_IPC]; + if (ipcLimit->mqCount >= ipcLimit->mqCountLimit) { + ipcLimit->mqFailedCount++; + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + run->limitStat.mqCount++; + ipcLimit->mqCount++; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +VOID OsIPCLimitMqFree(VOID) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + LosProcessCB *run = OsCurrProcessGet(); + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)run->plimits->limitsList[PROCESS_LIMITER_ID_IPC]; + ipcLimit->mqCount--; + run->limitStat.mqCount--; + SCHEDULER_UNLOCK(intSave); + return; +} + +UINT32 OsIPCLimitShmAlloc(UINT32 size) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + LosProcessCB *run = OsCurrProcessGet(); + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)run->plimits->limitsList[PROCESS_LIMITER_ID_IPC]; + if ((ipcLimit->shmSize + size) >= ipcLimit->shmSizeLimit) { + ipcLimit->shmFailedCount++; + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + run->limitStat.shmSize += size; + ipcLimit->shmSize += size; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +VOID OsIPCLimitShmFree(UINT32 size) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + LosProcessCB *run = OsCurrProcessGet(); + ProcIPCLimit *ipcLimit = (ProcIPCLimit *)run->plimits->limitsList[PROCESS_LIMITER_ID_IPC]; + ipcLimit->shmSize -= size; + run->limitStat.shmSize -= size; + SCHEDULER_UNLOCK(intSave); + return; +} + +#endif diff --git a/kernel/extended/plimit/los_ipclimit.h b/kernel/extended/plimit/los_ipclimit.h new file mode 100644 index 0000000000000000000000000000000000000000..d5ea14e31434f1a0deaf9bdd7a94489749a44aa7 --- /dev/null +++ b/kernel/extended/plimit/los_ipclimit.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022-2022 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. + */ + +#ifndef _LOS_IPCLIMIT_H +#define _LOS_IPCLIMIT_H + +#include "los_typedef.h" +#include "los_atomic.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef struct ProcIPCLimit { + Atomic rc; + UINT32 mqCount; + UINT32 mqFailedCount; + UINT32 mqCountLimit; + UINT32 shmSize; + UINT32 shmFailedCount; + UINT32 shmSizeLimit; + UINT64 migrateTime; +} ProcIPCLimit; + +enum IPCStatType { + IPC_STAT_TYPE_MQ = 0, + IPC_STAT_TYPE_SHM = 3, + IPC_STAT_TYPE_BUT // buttock +}; + +enum IPCStatOffset { + IPC_STAT_OFFSET_MQ = 0, + IPC_STAT_OFFSET_SHM = 3, + IPC_STAT_OFFSET_BUT // buttock +}; + +enum StatItem { + STAT_ITEM_TOTAL, + STAT_ITEM_FAILED, + STAT_ITEM_LIMIT, + STAT_ITEM_BUT // buttock +}; + +VOID OsIPCLimitInit(UINTPTR limite); +VOID *OsIPCLimitAlloc(VOID); +VOID OsIPCLimitFree(UINTPTR limite); +VOID OsIPCLimitCopy(UINTPTR dest, UINTPTR src); +BOOL OsIPCLimiteMigrateCheck(UINTPTR curr, UINTPTR parent); +VOID OsIPCLimitMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process); +BOOL OsIPCLimitAddProcessCheck(UINTPTR limit, UINTPTR process); +VOID OsIPCLimitAddProcess(UINTPTR limit, UINTPTR process); +VOID OsIPCLimitDelProcess(UINTPTR limit, UINTPTR process); +UINT32 OsIPCLimitSetMqLimit(ProcIPCLimit *ipcLimit, UINT32 value); +UINT32 OsIPCLimitSetShmLimit(ProcIPCLimit *ipcLimit, UINT32 value); +UINT32 OsIPCLimitMqAlloc(VOID); +VOID OsIPCLimitMqFree(VOID); +UINT32 OsIPCLimitShmAlloc(UINT32 size); +VOID OsIPCLimitShmFree(UINT32 size); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _LOS_IPCIMIT_H */ diff --git a/kernel/extended/plimit/los_memlimit.c b/kernel/extended/plimit/los_memlimit.c new file mode 100644 index 0000000000000000000000000000000000000000..2d473231cf9c85feed0e12ad47bae13636d3a562 --- /dev/null +++ b/kernel/extended/plimit/los_memlimit.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2022-2022 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 +#include +#include "los_config.h" +#include "los_hook.h" +#include "los_process_pri.h" +#include "los_plimits.h" + +#ifdef LOSCFG_KERNEL_MEM_PLIMIT +STATIC ProcMemLimiter *g_procMemLimiter = NULL; + +VOID OsMemLimiterInit(UINTPTR limite) +{ + ProcMemLimiter *procMemLimiter = (ProcMemLimiter *)limite; + procMemLimiter->limit = OS_NULL_INT; + g_procMemLimiter = procMemLimiter; +} + +VOID OsMemLimitSetLimit(UINT32 limit) +{ + g_procMemLimiter->limit = limit; +} + +VOID *OsMemLimiterAlloc(VOID) +{ + ProcMemLimiter *plimite = (ProcMemLimiter *)LOS_KernelMalloc(sizeof(ProcMemLimiter)); + if (plimite == NULL) { + return NULL; + } + (VOID)memset_s(plimite, sizeof(ProcMemLimiter), 0, sizeof(ProcMemLimiter)); + LOS_AtomicSet(&plimite->rc, 1); + return (VOID *)plimite; +} + +VOID OsMemLimiterFree(UINTPTR limite) +{ + ProcMemLimiter *plimite = (ProcMemLimiter *)limite; + if (plimite == NULL) { + return; + } + + LOS_AtomicDec(&plimite->rc); + if (LOS_AtomicRead(&plimite->rc) <= 0) { + LOS_KernelFree((VOID *)limite); + } +} + +VOID OsMemLimiterCopy(UINTPTR dest, UINTPTR src) +{ + ProcMemLimiter *plimiteDest = (ProcMemLimiter *)dest; + ProcMemLimiter *plimiteSrc = (ProcMemLimiter *)src; + plimiteDest->limit = plimiteSrc->limit; + return; +} + +BOOL MemLimiteMigrateCheck(UINTPTR curr, UINTPTR parent) +{ + ProcMemLimiter *currMemLimit = (ProcMemLimiter *)curr; + ProcMemLimiter *parentMemLimit = (ProcMemLimiter *)parent; + if ((currMemLimit->usage + parentMemLimit->usage) >= parentMemLimit->limit) { + return FALSE; + } + return TRUE; +} + +VOID OsMemLimiterMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process) +{ + ProcMemLimiter *currMemLimit = (ProcMemLimiter *)currLimit; + ProcMemLimiter *parentMemLimit = (ProcMemLimiter *)parentLimit; + LosProcessCB *pcb = (LosProcessCB *)process; + + if (pcb == NULL) { + parentMemLimit->usage += currMemLimit->usage; + parentMemLimit->failcnt += currMemLimit->failcnt; + if (parentMemLimit->peak < parentMemLimit->usage) { + parentMemLimit->peak = parentMemLimit->usage; + } + LOS_AtomicInc(&parentMemLimit->rc); + return; + } + + parentMemLimit->usage -= pcb->limitStat.memUsed; + currMemLimit->usage += pcb->limitStat.memUsed; +} + +BOOL OsMemLimitAddProcessCheck(UINTPTR limit, UINTPTR process) +{ + ProcMemLimiter *memLimit = (ProcMemLimiter *)limit; + LosProcessCB *pcb = (LosProcessCB *)process; + if ((memLimit->usage + pcb->limitStat.memUsed) > memLimit->limit) { + return FALSE; + } + return TRUE; +} + +VOID OsMemLimitAddProcess(UINTPTR limit, UINTPTR process) +{ + LosProcessCB *pcb = (LosProcessCB *)process; + ProcMemLimiter *plimits = (ProcMemLimiter *)limit; + plimits->usage += pcb->limitStat.memUsed; + if (plimits->peak < plimits->usage) { + plimits->peak = plimits->usage; + } + return; +} + +VOID OsMemLimitDelProcess(UINTPTR limit, UINTPTR process) +{ + LosProcessCB *pcb = (LosProcessCB *)process; + ProcMemLimiter *plimits = (ProcMemLimiter *)limit; + + plimits->usage -= pcb->limitStat.memUsed; + return; +} + +UINT32 OsMemLimitSetMemLimit(ProcMemLimiter *memLimit, UINT64 value) +{ + UINT32 intSave; + if ((memLimit == NULL) || (value == 0)) { + return EINVAL; + } + + if (memLimit == g_procMemLimiter) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + if (value < memLimit->usage) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + memLimit->limit = value; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +#define MEM_LIMIT_LOCK(state, locked) do { \ + if (SCHEDULER_HELD()) { \ + locked = TRUE; \ + } else { \ + SCHEDULER_LOCK(state); \ + } \ +} while (0) + +#define MEM_LIMIT_UNLOCK(state, locked) do { \ + if (!locked) { \ + SCHEDULER_UNLOCK(state); \ + } \ +} while (0) + +UINT32 OsMemLimitCheckAndMemAdd(UINT32 size) +{ + UINT32 intSave; + BOOL locked = FALSE; + MEM_LIMIT_LOCK(intSave, locked); + LosProcessCB *run = OsCurrProcessGet(); + UINT32 currProcessID = run->processID; + if ((run == NULL) || (run->plimits == NULL)) { + MEM_LIMIT_UNLOCK(intSave, locked); + return LOS_OK; + } + + ProcMemLimiter *memLimit = (ProcMemLimiter *)run->plimits->limitsList[PROCESS_LIMITER_ID_MEM]; + if ((memLimit->usage + size) > memLimit->limit) { + memLimit->failcnt++; + MEM_LIMIT_UNLOCK(intSave, locked); + PRINT_ERR("plimits: process %u adjust the memory limit of Plimits group\n", currProcessID); + return ENOMEM; + } + + memLimit->usage += size; + run->limitStat.memUsed += size; + if (memLimit->peak < memLimit->usage) { + memLimit->peak = memLimit->usage; + } + MEM_LIMIT_UNLOCK(intSave, locked); + return LOS_OK; +} + +VOID OsMemLimitMemFree(UINT32 size) +{ + UINT32 intSave; + BOOL locked = FALSE; + MEM_LIMIT_LOCK(intSave, locked); + LosProcessCB *run = OsCurrProcessGet(); + if ((run == NULL) || (run->plimits == NULL)) { + MEM_LIMIT_UNLOCK(intSave, locked); + return; + } + + ProcMemLimiter *memLimit = (ProcMemLimiter *)run->plimits->limitsList[PROCESS_LIMITER_ID_MEM]; + if (run->limitStat.memUsed > size) { + run->limitStat.memUsed -= size; + memLimit->usage -= size; + } + MEM_LIMIT_UNLOCK(intSave, locked); +} +#endif diff --git a/kernel/extended/plimit/los_memlimit.h b/kernel/extended/plimit/los_memlimit.h new file mode 100644 index 0000000000000000000000000000000000000000..35c5ee9e572e681737000db151b3a674ca063eab --- /dev/null +++ b/kernel/extended/plimit/los_memlimit.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022-2022 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. + */ + +#ifndef _LOS_MEMLIMIT_H +#define _LOS_MEMLIMIT_H + +#include "los_typedef.h" +#include "los_atomic.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef struct ProcMemLimiter { + Atomic rc; + UINT64 usage; + UINT64 limit; + UINT64 peak; + UINT32 failcnt; +} ProcMemLimiter; + +VOID OsMemLimiterInit(UINTPTR limite); +VOID *OsMemLimiterAlloc(VOID); +VOID OsMemLimiterFree(UINTPTR limite); +VOID OsMemLimiterCopy(UINTPTR dest, UINTPTR src); +BOOL MemLimiteMigrateCheck(UINTPTR curr, UINTPTR parent); +VOID OsMemLimiterMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process); +BOOL OsMemLimitAddProcessCheck(UINTPTR limit, UINTPTR process); +VOID OsMemLimitAddProcess(UINTPTR limit, UINTPTR process); +VOID OsMemLimitDelProcess(UINTPTR limit, UINTPTR process); +UINT32 OsMemLimitSetMemLimit(ProcMemLimiter *memLimit, UINT64 value); +VOID OsMemLimitSetLimit(UINTPTR limit); +UINT32 OsMemLimitCheckAndMemAdd(UINT32 size); +VOID OsMemLimitMemFree(UINT32 size); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _LOS_MEMLIMIT_H */ diff --git a/kernel/extended/plimit/los_plimits.c b/kernel/extended/plimit/los_plimits.c new file mode 100644 index 0000000000000000000000000000000000000000..8f357016a472a66adbccc0aa320286c41a3e9a55 --- /dev/null +++ b/kernel/extended/plimit/los_plimits.c @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2023-2023 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 "los_base.h" +#include "los_process_pri.h" +#include "hal_timer.h" +#include "los_plimits.h" + +#ifdef LOSCFG_KERNEL_PLIMITS +typedef struct PlimiteOperations { + VOID (*LimiterInit)(UINTPTR); + VOID *(*LimiterAlloc)(VOID); + VOID (*LimiterFree)(UINTPTR); + VOID (*LimiterCopy)(UINTPTR, UINTPTR); + BOOL (*LimiterAddProcessCheck)(UINTPTR, UINTPTR); + VOID (*LimiterAddProcess)(UINTPTR, UINTPTR); + VOID (*LimiterDelProcess)(UINTPTR, UINTPTR); + BOOL (*LimiterMigrateCheck)(UINTPTR, UINTPTR); + VOID (*LimiterMigrate)(UINTPTR, UINTPTR, UINTPTR); +} PlimiteOperations; + +static PlimiteOperations g_limiteOps[PROCESS_LIMITER_COUNT] = { + [PROCESS_LIMITER_ID_PIDS] = { + .LimiterInit = PidLimiterInit, + .LimiterAlloc = PidLimiterAlloc, + .LimiterFree = PidLimterFree, + .LimiterCopy = PidLimiterCopy, + .LimiterAddProcessCheck = OsPidLimitAddProcessCheck, + .LimiterAddProcess = OsPidLimitAddProcess, + .LimiterDelProcess = OsPidLimitDelProcess, + .LimiterMigrateCheck = PidLimitMigrateCheck, + .LimiterMigrate = OsPidLimiterMigrate, + }, +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + [PROCESS_LIMITER_ID_MEM] = { + .LimiterInit = OsMemLimiterInit, + .LimiterAlloc = OsMemLimiterAlloc, + .LimiterFree = OsMemLimiterFree, + .LimiterCopy = OsMemLimiterCopy, + .LimiterAddProcessCheck = OsMemLimitAddProcessCheck, + .LimiterAddProcess = OsMemLimitAddProcess, + .LimiterDelProcess = OsMemLimitDelProcess, + .LimiterMigrateCheck = MemLimiteMigrateCheck, + .LimiterMigrate = OsMemLimiterMigrate, + }, +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + [PROCESS_LIMITER_ID_SCHED] = { + .LimiterInit = OsSchedLimitInit, + .LimiterAlloc = OsSchedLimitAlloc, + .LimiterFree = OsSchedLimitFree, + .LimiterCopy = OsSchedLimitCopy, + .LimiterAddProcessCheck = NULL, + .LimiterAddProcess = NULL, + .LimiterDelProcess = NULL, + .LimiterMigrateCheck = NULL, + .LimiterMigrate = OsSchedLimitMigrate, + }, +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT + [PROCESS_LIMITER_ID_DEV] = { + .LimiterInit = OsDevLimitInit, + .LimiterAlloc = OsDevLimitAlloc, + .LimiterFree = OsDevLimitFree, + .LimiterCopy = OsDevLimitCopy, + .LimiterAddProcessCheck = NULL, + .LimiterAddProcess = NULL, + .LimiterDelProcess = NULL, + .LimiterMigrateCheck = NULL, + .LimiterMigrate = OsDevLimitMigrate, + }, +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + [PROCESS_LIMITER_ID_IPC] = { + .LimiterInit = OsIPCLimitInit, + .LimiterAlloc = OsIPCLimitAlloc, + .LimiterFree = OsIPCLimitFree, + .LimiterCopy = OsIPCLimitCopy, + .LimiterAddProcessCheck = OsIPCLimitAddProcessCheck, + .LimiterAddProcess = OsIPCLimitAddProcess, + .LimiterDelProcess = OsIPCLimitDelProcess, + .LimiterMigrateCheck = OsIPCLimiteMigrateCheck, + .LimiterMigrate = OsIPCLimitMigrate, + }, +#endif +}; + +STATIC ProcLimiterSet *g_rootPLimite = NULL; + +ProcLimiterSet *OsRootPLimitsGet(VOID) +{ + return g_rootPLimite; +} + +UINT32 OsProcLimiterSetInit(VOID) +{ + g_rootPLimite = (ProcLimiterSet *)LOS_KernelMalloc(sizeof(ProcLimiterSet)); + if (g_rootPLimite == NULL) { + return ENOMEM; + } + (VOID)memset_s(g_rootPLimite, sizeof(ProcLimiterSet), 0, sizeof(ProcLimiterSet)); + + LOS_ListInit(&g_rootPLimite->childList); + LOS_ListInit(&g_rootPLimite->processList); + + ProcLimiterSet *procLimiterSet = g_rootPLimite; + for (INT32 plimiteID = 0; plimiteID < PROCESS_LIMITER_COUNT; ++plimiteID) { + procLimiterSet->limitsList[plimiteID] = (UINTPTR)g_limiteOps[plimiteID].LimiterAlloc(); + if (procLimiterSet->limitsList[plimiteID] == (UINTPTR)NULL) { + OsPLimitsFree(procLimiterSet); + return ENOMEM; + } + + if (g_limiteOps[plimiteID].LimiterInit != NULL) { + g_limiteOps[plimiteID].LimiterInit(procLimiterSet->limitsList[plimiteID]); + } + } + return LOS_OK; +} + +STATIC UINT32 PLimitsAddProcess(ProcLimiterSet *plimits, LosProcessCB *processCB) +{ + UINT32 limitsID; + if (plimits == NULL) { + plimits = g_rootPLimite; + } + + if (processCB->plimits == g_rootPLimite) { + return EPERM; + } + + if (processCB->plimits == plimits) { + return LOS_OK; + } + + for (limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) { + if (g_limiteOps[limitsID].LimiterAddProcessCheck == NULL) { + continue; + } + + if (!g_limiteOps[limitsID].LimiterAddProcessCheck(plimits->limitsList[limitsID], (UINTPTR)processCB)) { + return EACCES; + } + } + + for (limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) { + if (g_limiteOps[limitsID].LimiterAddProcess == NULL) { + continue; + } + g_limiteOps[limitsID].LimiterAddProcess(plimits->limitsList[limitsID], (UINTPTR)processCB); + } + + LOS_ListTailInsert(&plimits->processList, &processCB->plimitsList); + plimits->pidCount++; + processCB->plimits = plimits; + return LOS_OK; +} + +UINT32 OsPLimitsAddProcess(ProcLimiterSet *plimits, LosProcessCB *processCB) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + UINT32 ret = PLimitsAddProcess(plimits, processCB); + SCHEDULER_UNLOCK(intSave); + return ret; +} + +UINT32 OsPLimitsAddPid(ProcLimiterSet *plimits, UINT32 pid) +{ + UINT32 intSave, ret; + if ((plimits == NULL) || OS_PID_CHECK_INVALID(pid) || (pid == 0)) { + return EINVAL; + } + + if (plimits == g_rootPLimite) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + LosProcessCB *processCB = OS_PCB_FROM_PID((unsigned int)pid); + if (OsProcessIsInactive(processCB)) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + ret = PLimitsAddProcess(plimits, processCB); + SCHEDULER_UNLOCK(intSave); + return ret; +} + +STATIC VOID PLimitsDeleteProcess(LosProcessCB *processCB) +{ + if ((processCB == NULL) || (processCB->plimits == NULL)) { + return; + } + + ProcLimiterSet *plimits = processCB->plimits; + for (UINT32 limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) { + if (g_limiteOps[limitsID].LimiterDelProcess == NULL) { + continue; + } + g_limiteOps[limitsID].LimiterDelProcess(plimits->limitsList[limitsID], (UINTPTR)processCB); + } + plimits->pidCount--; + LOS_ListDelete(&processCB->plimitsList); + processCB->plimits = NULL; + return; +} + +VOID OsPLimitsDeleteProcess(LosProcessCB *processCB) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + PLimitsDeleteProcess(processCB); + SCHEDULER_UNLOCK(intSave); +} + +UINT32 OsPLimitsPidsGet(const ProcLimiterSet *plimits, UINT32 *pids, UINT32 size) +{ + UINT32 intSave; + LosProcessCB *processCB = NULL; + UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT32); + if ((plimits == NULL) || (pids == NULL) || (size < minSize)) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList; + if (LOS_ListEmpty(listHead)) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) { + pids[OsGetPid(processCB)] = 1; + } + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +STATIC VOID PLimitsProcessMerge(ProcLimiterSet *currPLimits, ProcLimiterSet *parentPLimits) +{ + LOS_DL_LIST *head = &currPLimits->processList; + while (!LOS_ListEmpty(head)) { + LosProcessCB *processCB = LOS_DL_LIST_ENTRY(head->pstNext, LosProcessCB, plimitsList); + PLimitsDeleteProcess(processCB); + PLimitsAddProcess(parentPLimits, processCB); + } + LOS_ListDelete(&currPLimits->childList); + currPLimits->parent = NULL; + return; +} + +STATIC UINT32 PLimitsMigrateCheck(ProcLimiterSet *currPLimits, ProcLimiterSet *parentPLimits) +{ + for (UINT32 limiteID = 0; limiteID < PROCESS_LIMITER_COUNT; limiteID++) { + UINTPTR currLimit = currPLimits->limitsList[limiteID]; + UINTPTR parentLimit = parentPLimits->limitsList[limiteID]; + if (g_limiteOps[limiteID].LimiterMigrateCheck == NULL) { + continue; + } + + if (!g_limiteOps[limiteID].LimiterMigrateCheck(currLimit, parentLimit)) { + return EPERM; + } + } + return LOS_OK; +} + +UINT32 OsPLimitsFree(ProcLimiterSet *currPLimits) +{ + UINT32 intSave, ret; + if (currPLimits == NULL) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + ProcLimiterSet *parentPLimits = currPLimits->parent; + ret = PLimitsMigrateCheck(currPLimits, parentPLimits); + if (ret != LOS_OK) { + SCHEDULER_UNLOCK(intSave); + return ret; + } + + PLimitsProcessMerge(currPLimits, parentPLimits); + SCHEDULER_UNLOCK(intSave); + + for (INT32 limiteID = 0; limiteID < PROCESS_LIMITER_COUNT; ++limiteID) { + UINTPTR procLimiter = currPLimits->limitsList[limiteID]; + if (g_limiteOps[limiteID].LimiterFree != NULL) { + g_limiteOps[limiteID].LimiterFree(procLimiter); + } + } + LOS_KernelFree(currPLimits); + return LOS_OK; +} + +ProcLimiterSet *OsPLimitsCreate(ProcLimiterSet *parentPLimits) +{ + UINT32 intSave; + + ProcLimiterSet *newPLimits = (ProcLimiterSet *)LOS_MemAlloc(m_aucSysMem1, sizeof(ProcLimiterSet)); + if (newPLimits == NULL) { + return NULL; + } + (VOID)memset_s(newPLimits, sizeof(ProcLimiterSet), 0, sizeof(ProcLimiterSet)); + LOS_ListInit(&newPLimits->childList); + LOS_ListInit(&newPLimits->processList); + + SCHEDULER_LOCK(intSave); + newPLimits->parent = parentPLimits; + newPLimits->level = parentPLimits->level + 1; + newPLimits->mask = parentPLimits->mask; + + for (INT32 plimiteID = 0; plimiteID < PROCESS_LIMITER_COUNT; ++plimiteID) { + newPLimits->limitsList[plimiteID] = (UINTPTR)g_limiteOps[plimiteID].LimiterAlloc(); + if (newPLimits->limitsList[plimiteID] == (UINTPTR)NULL) { + SCHEDULER_UNLOCK(intSave); + OsPLimitsFree(newPLimits); + return NULL; + } + + if (g_limiteOps[plimiteID].LimiterCopy != NULL) { + g_limiteOps[plimiteID].LimiterCopy(newPLimits->limitsList[plimiteID], + parentPLimits->limitsList[plimiteID]); + } + } + LOS_ListTailInsert(&g_rootPLimite->childList, &newPLimits->childList); + + (VOID)PLimitsDeleteProcess(OsCurrProcessGet()); + (VOID)PLimitsAddProcess(newPLimits, OsCurrProcessGet()); + SCHEDULER_UNLOCK(intSave); + return newPLimits; +} + +UINT32 OsPLimitsAddLimiters(ProcLimiterSet *procLimiterSet, enum ProcLimiterID plimiteID) +{ + UINT32 intSave; + UINT32 mask = BIT(plimiteID); + if ((procLimiterSet == NULL) || (plimiteID > PROCESS_LIMITER_COUNT)) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + if (procLimiterSet->level == 0) { + SCHEDULER_UNLOCK(intSave); + return EPERM; + } + + if (procLimiterSet->mask & mask) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + UINTPTR currLimit = procLimiterSet->limitsList[plimiteID]; + UINTPTR parentPLimit = procLimiterSet->parent->limitsList[plimiteID]; + procLimiterSet->limitsList[plimiteID] = (UINTPTR)g_limiteOps[plimiteID].LimiterAlloc(); + if (procLimiterSet->limitsList[plimiteID] == (UINTPTR)NULL) { + procLimiterSet->limitsList[plimiteID] = parentPLimit; + SCHEDULER_UNLOCK(intSave); + return ENOMEM; + } + + g_limiteOps[plimiteID].LimiterCopy(procLimiterSet->limitsList[plimiteID], parentPLimit); + g_limiteOps[plimiteID].LimiterMigrate(procLimiterSet->limitsList[plimiteID], + parentPLimit, (UINTPTR)OsCurrProcessGet()); + g_limiteOps[plimiteID].LimiterFree(currLimit); + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +UINT32 OsPLimitsDeleteLimiters(ProcLimiterSet *procLimiterSet, enum ProcLimiterID plimiteID, UINT32 *mask) +{ + UINT32 intSave; + + if ((procLimiterSet == NULL) || (plimiteID > PROCESS_LIMITER_COUNT) || (mask == NULL)) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + if (!(procLimiterSet->mask & BIT(plimiteID))) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + if (procLimiterSet->level == 0) { + SCHEDULER_UNLOCK(intSave); + return EPERM; + } + + UINTPTR currLimit = procLimiterSet->limitsList[plimiteID]; + UINTPTR parentPLimit = procLimiterSet->parent->limitsList[plimiteID]; + if ((g_limiteOps[plimiteID].LimiterMigrateCheck != NULL) && + !g_limiteOps[plimiteID].LimiterMigrateCheck(currLimit, parentPLimit)) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + g_limiteOps[plimiteID].LimiterMigrate(currLimit, parentPLimit, 0); + procLimiterSet->limitsList[plimiteID] = parentPLimit; + g_limiteOps[plimiteID].LimiterFree(currLimit); + + procLimiterSet->mask &= (~BIT(plimiteID)); + *mask = procLimiterSet->mask; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +#ifdef LOSCFG_KERNEL_MEM_PLIMIT +UINT32 OsPLimitsMemUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size) +{ + UINT32 intSave; + LosProcessCB *processCB = NULL; + UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT64) + sizeof(ProcMemLimiter); + ProcMemLimiter *memLimit = (ProcMemLimiter *)usage; + UINT64 *memSuage = (UINT64 *)((UINTPTR)usage + sizeof(ProcMemLimiter)); + if ((plimits == NULL) || (usage == NULL) || (size < minSize)) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(memLimit, sizeof(ProcMemLimiter), + (VOID *)plimits->limitsList[PROCESS_LIMITER_ID_MEM], sizeof(ProcMemLimiter)); + LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList; + if (LOS_ListEmpty(listHead)) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) { + memSuage[OsGetPid(processCB)] = processCB->limitStat.memUsed; + } + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} +#endif + +#ifdef LOSCFG_KERNEL_IPC_PLIMIT +UINT32 OsPLimitsIPCStatGet(ProcLimiterSet *plimits, ProcIPCLimit *ipc, UINT32 size) +{ + UINT32 intSave; + if ((plimits == NULL) || (ipc == NULL) || (size != sizeof(ProcIPCLimit))) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + (VOID)memcpy_s(ipc, sizeof(ProcIPCLimit), + (VOID *)plimits->limitsList[PROCESS_LIMITER_ID_IPC], sizeof(ProcIPCLimit)); + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} +#endif + +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT +UINT32 OsPLimitsSchedUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size) +{ + UINT32 intSave; + LosProcessCB *processCB = NULL; + UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT64); + if ((plimits == NULL) || (usage == NULL) || (size < minSize)) { + return EINVAL; + } + + SCHEDULER_LOCK(intSave); + LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList; + if (LOS_ListEmpty(listHead)) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) { + usage[OsGetPid(processCB)] = processCB->limitStat.allRuntime; + } + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} +#endif +#endif diff --git a/kernel/extended/plimit/los_plimits.h b/kernel/extended/plimit/los_plimits.h new file mode 100644 index 0000000000000000000000000000000000000000..6c06540e0580e35affa5007feaa01e980d1096db --- /dev/null +++ b/kernel/extended/plimit/los_plimits.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023-2023 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. + */ + +#ifndef _LOS_PLIMITS_H +#define _LOS_PLIMITS_H + +#include "los_list.h" +#include "los_typedef.h" +#include "los_processlimit.h" +#include "los_memlimit.h" +#include "los_ipclimit.h" +#include "los_devicelimit.h" +#include "los_schedlimit.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +/* proc limit set lock */ +#define PLIMITS_MIN_PERIOD_IN_US 1000000 +#define PLIMITS_MIN_QUOTA_IN_US 1 +#define PLIMITS_DELETE_WAIT_TIME 1000 +typedef struct ProcessCB LosProcessCB; + +enum ProcLimiterID { + PROCESS_LIMITER_ID_PIDS = 0, +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + PROCESS_LIMITER_ID_MEM, +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + PROCESS_LIMITER_ID_SCHED, +#endif +#ifdef LOSCFG_KERNEL_DEV_PLIMIT + PROCESS_LIMITER_ID_DEV, +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + PROCESS_LIMITER_ID_IPC, +#endif + PROCESS_LIMITER_COUNT, +}; + +typedef struct { +#ifdef LOSCFG_KERNEL_MEM_PLIMIT + UINT64 memUsed; +#endif +#ifdef LOSCFG_KERNEL_IPC_PLIMIT + UINT32 mqCount; + UINT32 shmSize; +#endif +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT + UINT64 allRuntime; +#endif +} PLimitsData; + +typedef struct TagPLimiterSet { + struct TagPLimiterSet *parent; /* plimite parent */ + LOS_DL_LIST childList; /* plimite childList */ + LOS_DL_LIST processList; + UINT32 pidCount; + UINTPTR limitsList[PROCESS_LIMITER_COUNT]; /* plimite list */ + UINT32 mask; /* each bit indicates that a limite exists */ + UINT8 level; /* plimits hierarchy level */ +} ProcLimiterSet; + +typedef struct ProcessCB LosProcessCB; +ProcLimiterSet *OsRootPLimitsGet(VOID); +UINT32 OsPLimitsAddProcess(ProcLimiterSet *plimits, LosProcessCB *processCB); +UINT32 OsPLimitsAddPid(ProcLimiterSet *plimits, UINT32 pid); +VOID OsPLimitsDeleteProcess(LosProcessCB *processCB); +UINT32 OsPLimitsPidsGet(const ProcLimiterSet *plimits, UINT32 *pids, UINT32 size); +UINT32 OsPLimitsFree(ProcLimiterSet *currPLimits); +ProcLimiterSet *OsPLimitsCreate(ProcLimiterSet *parentProcLimiterSet); +UINT32 OsProcLimiterSetInit(VOID); + +UINT32 OsPLimitsAddLimiters(ProcLimiterSet *procLimiterSet, enum ProcLimiterID plimiteID); +UINT32 OsPLimitsDeleteLimiters(ProcLimiterSet *procLimiterSet, enum ProcLimiterID plimiteID, UINT32 *mask); + +UINT32 OsPLimitsMemUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size); +UINT32 OsPLimitsIPCStatGet(ProcLimiterSet *plimits, ProcIPCLimit *ipc, UINT32 size); +UINT32 OsPLimitsSchedUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _LOS_PLIMITS_H */ diff --git a/kernel/extended/plimit/los_processlimit.c b/kernel/extended/plimit/los_processlimit.c new file mode 100644 index 0000000000000000000000000000000000000000..7211f9512b8c8ab96c3bea467c00cad5b429b5df --- /dev/null +++ b/kernel/extended/plimit/los_processlimit.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2023-2023 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 "los_config.h" +#include "los_process_pri.h" +#include "los_process.h" +#include "los_plimits.h" +#include "los_task_pri.h" +#include "los_processlimit.h" + +#ifdef LOSCFG_KERNEL_PLIMITS +STATIC PidLimit *g_rootPidLimit = NULL; + +VOID PidLimiterInit(UINTPTR limit) +{ + PidLimit *pidLimit = (PidLimit *)limit; + if (pidLimit == NULL) { + return; + } + + pidLimit->pidLimit = LOS_GetSystemProcessMaximum(); + pidLimit->priorityLimit = OS_USER_PROCESS_PRIORITY_HIGHEST; + g_rootPidLimit = pidLimit; +} + +VOID *PidLimiterAlloc(VOID) +{ + PidLimit *plimite = (PidLimit *)LOS_KernelMalloc(sizeof(PidLimit)); + if (plimite == NULL) { + return NULL; + } + (VOID)memset_s(plimite, sizeof(PidLimit), 0, sizeof(PidLimit)); + LOS_AtomicSet(&plimite->rc, 1); + return (VOID *)plimite; +} + +VOID PidLimterFree(UINTPTR limit) +{ + PidLimit *pidLimit = (PidLimit *)limit; + if (pidLimit == NULL) { + return; + } + + LOS_AtomicDec(&pidLimit->rc); + if (LOS_AtomicRead(&pidLimit->rc) <= 0) { + LOS_KernelFree((VOID *)limit); + } +} + +BOOL PidLimitMigrateCheck(UINTPTR curr, UINTPTR parent) +{ + PidLimit *currPidLimit = (PidLimit *)curr; + PidLimit *parentPidLimit = (PidLimit *)parent; + if ((currPidLimit == NULL) || (parentPidLimit == NULL)) { + return FALSE; + } + + if ((currPidLimit->pidCount + parentPidLimit->pidCount) >= parentPidLimit->pidLimit) { + return FALSE; + } + return TRUE; +} + +VOID OsPidLimiterMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process) +{ + (VOID)currLimit; + + PidLimit *parentPidLimit = (PidLimit *)parentLimit; + LosProcessCB *pcb = (LosProcessCB *)process; + + if (pcb == NULL) { + LOS_AtomicInc(&parentPidLimit->rc); + } +} + +BOOL OsPidLimitAddProcessCheck(UINTPTR limit, UINTPTR process) +{ + (VOID)process; + PidLimit *pidLimit = (PidLimit *)limit; + if (pidLimit->pidCount >= pidLimit->pidLimit) { + return FALSE; + } + return TRUE; +} + +VOID OsPidLimitAddProcess(UINTPTR limit, UINTPTR process) +{ + (VOID)process; + PidLimit *plimits = (PidLimit *)limit; + + plimits->pidCount++; + return; +} + +VOID OsPidLimitDelProcess(UINTPTR limit, UINTPTR process) +{ + (VOID)process; + PidLimit *plimits = (PidLimit *)limit; + + plimits->pidCount--; + return; +} + +VOID PidLimiterCopy(UINTPTR curr, UINTPTR parent) +{ + PidLimit *currPidLimit = (PidLimit *)curr; + PidLimit *parentPidLimit = (PidLimit *)parent; + if ((currPidLimit == NULL) || (parentPidLimit == NULL)) { + return; + } + + currPidLimit->pidLimit = parentPidLimit->pidLimit; + currPidLimit->priorityLimit = parentPidLimit->priorityLimit; + currPidLimit->pidCount = 0; + return; +} + +UINT32 PidLimitSetPidLimit(PidLimit *pidLimit, UINT32 pidMax) +{ + UINT32 intSave; + + if ((pidLimit == NULL) || (pidMax > LOS_GetSystemProcessMaximum())) { + return EINVAL; + } + + if (pidLimit == g_rootPidLimit) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + if (pidLimit->pidCount >= pidMax) { + SCHEDULER_UNLOCK(intSave); + return EPERM; + } + + pidLimit->pidLimit = pidMax; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +UINT32 PidLimitSetPriorityLimit(PidLimit *pidLimit, UINT32 priority) +{ + UINT32 intSave; + + if ((pidLimit == NULL) || + (priority < OS_USER_PROCESS_PRIORITY_HIGHEST) || + (priority > OS_PROCESS_PRIORITY_LOWEST)) { + return EINVAL; + } + + if (pidLimit == g_rootPidLimit) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + pidLimit->priorityLimit = priority; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +UINT16 OsPidLimitGetPriorityLimit(VOID) +{ + UINT32 intSave; + SCHEDULER_LOCK(intSave); + LosProcessCB *run = OsCurrProcessGet(); + PidLimit *pidLimit = (PidLimit *)run->plimits->limitsList[PROCESS_LIMITER_ID_PIDS]; + UINT16 priority = pidLimit->priorityLimit; + SCHEDULER_UNLOCK(intSave); + return priority; +} +#endif diff --git a/kernel/extended/plimit/los_processlimit.h b/kernel/extended/plimit/los_processlimit.h new file mode 100644 index 0000000000000000000000000000000000000000..997218a07095aa893e7612964fa4c8052427d4e1 --- /dev/null +++ b/kernel/extended/plimit/los_processlimit.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023-2023 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. + */ + +#ifndef _LOS_PROCESSLIMIT_H +#define _LOS_PROCESSLIMIT_H + +#include "los_list.h" +#include "los_typedef.h" +#include "los_atomic.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef struct PidLimit { + Atomic rc; + UINT32 pidLimit; + UINT32 priorityLimit; + UINT32 pidCount; +} PidLimit; + +VOID PidLimiterInit(UINTPTR limit); +VOID *PidLimiterAlloc(VOID); +VOID PidLimterFree(UINTPTR limit); +VOID PidLimiterCopy(UINTPTR curr, UINTPTR parent); +BOOL PidLimitMigrateCheck(UINTPTR curr, UINTPTR parent); +VOID OsPidLimiterMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process); +BOOL OsPidLimitAddProcessCheck(UINTPTR limit, UINTPTR process); +VOID OsPidLimitAddProcess(UINTPTR limit, UINTPTR process); +VOID OsPidLimitDelProcess(UINTPTR limit, UINTPTR process); +UINT32 PidLimitSetPidLimit(PidLimit *pidLimit, UINT32 pidMax); +UINT32 PidLimitSetPriorityLimit(PidLimit *pidLimit, UINT32 priority); +UINT16 OsPidLimitGetPriorityLimit(VOID); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif diff --git a/kernel/extended/plimit/los_schedlimit.c b/kernel/extended/plimit/los_schedlimit.c new file mode 100644 index 0000000000000000000000000000000000000000..acdf881f924073ea387af21fb6788abfada11b33 --- /dev/null +++ b/kernel/extended/plimit/los_schedlimit.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2023-2023 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 "los_schedlimit.h" +#include "los_process_pri.h" + +#ifdef LOSCFG_KERNEL_SCHED_PLIMIT +STATIC ProcSchedLimiter *g_procSchedLimit = NULL; + +VOID OsSchedLimitInit(UINTPTR limit) +{ + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)limit; + schedLimit->period = 0; + schedLimit->quota = 0; + g_procSchedLimit = schedLimit; +} + +VOID *OsSchedLimitAlloc(VOID) +{ + ProcSchedLimiter *plimit = (ProcSchedLimiter *)LOS_KernelMalloc(sizeof(ProcSchedLimiter)); + if (plimit == NULL) { + return NULL; + } + (VOID)memset_s(plimit, sizeof(ProcSchedLimiter), 0, sizeof(ProcSchedLimiter)); + LOS_AtomicSet(&plimit->rc, 1); + return (VOID *)plimit; +} + +VOID OsSchedLimitFree(UINTPTR limit) +{ + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)limit; + if (schedLimit == NULL) { + return; + } + + LOS_AtomicDec(&schedLimit->rc); + if (LOS_AtomicRead(&schedLimit->rc) <= 0) { + LOS_KernelFree((VOID *)limit); + } +} + +VOID OsSchedLimitCopy(UINTPTR dest, UINTPTR src) +{ + ProcSchedLimiter *plimitDest = (ProcSchedLimiter *)dest; + ProcSchedLimiter *plimitSrc = (ProcSchedLimiter *)src; + plimitDest->period = plimitSrc->period; + plimitDest->quota = plimitSrc->quota; + return; +} + +VOID OsSchedLimitMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process) +{ + (VOID)currLimit; + ProcSchedLimiter *parentSchedLimit = (ProcSchedLimiter *)parentLimit; + LosProcessCB *pcb = (LosProcessCB *)process; + if (pcb == NULL) { + LOS_AtomicInc(&parentSchedLimit->rc); + } +} + +VOID OsSchedLimitUpdateRuntime(LosTaskCB *runTask, UINT64 currTime, INT32 incTime) +{ + LosProcessCB *run = (LosProcessCB *)runTask->processCB; + if ((run == NULL) || (run->plimits == NULL)) { + return; + } + + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)run->plimits->limitsList[PROCESS_LIMITER_ID_SCHED]; + + run->limitStat.allRuntime += incTime; + if ((schedLimit->period <= 0) || (schedLimit->quota <= 0)) { + return; + } + + if ((schedLimit->startTime <= currTime) && (schedLimit->allRuntime < schedLimit->quota)) { + schedLimit->allRuntime += incTime; + return; + } + + if (schedLimit->startTime <= currTime) { + schedLimit->startTime = currTime + schedLimit->period; + schedLimit->allRuntime = 0; + } +} + +BOOL OsSchedLimitCheckTime(LosTaskCB *task) +{ + UINT64 currTime = OsGetCurrSchedTimeCycle(); + LosProcessCB *processCB = (LosProcessCB *)task->processCB; + if ((processCB == NULL) || (processCB->plimits == NULL)) { + return TRUE; + } + ProcSchedLimiter *schedLimit = (ProcSchedLimiter *)processCB->plimits->limitsList[PROCESS_LIMITER_ID_SCHED]; + if (schedLimit->startTime >= currTime) { + return FALSE; + } + return TRUE; +} + +UINT32 OsSchedLimitSetPeriod(ProcSchedLimiter *schedLimit, UINT64 value) +{ + UINT32 intSave; + if (schedLimit == NULL) { + return EINVAL; + } + + if (schedLimit == g_procSchedLimit) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + schedLimit->period = value; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} + +UINT32 OsSchedLimitSetQuota(ProcSchedLimiter *schedLimit, UINT64 value) +{ + UINT32 intSave; + if (schedLimit == NULL) { + return EINVAL; + } + + if (schedLimit == g_procSchedLimit) { + return EPERM; + } + + SCHEDULER_LOCK(intSave); + if (value > (UINT64)schedLimit->period) { + SCHEDULER_UNLOCK(intSave); + return EINVAL; + } + + schedLimit->quota = value; + SCHEDULER_UNLOCK(intSave); + return LOS_OK; +} +#endif diff --git a/kernel/extended/plimit/los_schedlimit.h b/kernel/extended/plimit/los_schedlimit.h new file mode 100644 index 0000000000000000000000000000000000000000..13ac9daa9a9c98c785d13e78a16ed79953e47d22 --- /dev/null +++ b/kernel/extended/plimit/los_schedlimit.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-2022 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. + */ + +#ifndef _LOS_SCHEDLIMIT_H +#define _LOS_SCHEDLIMIT_H + +#include "los_typedef.h" +#include "los_atomic.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define CORE_US_PER_SECOND (1000 * 1000) /* 1000 * 1000 us per second */ +typedef struct TagTaskCB LosTaskCB; + +typedef struct ProcSchedLimiter { + Atomic rc; + UINT64 startTime; + UINT64 endTime; + UINT64 period; + UINT64 quota; + UINT64 allRuntime; + UINT64 overrunTime; + UINT64 stat; +} ProcSchedLimiter; + +VOID OsSchedLimitInit(UINTPTR limit); +VOID *OsSchedLimitAlloc(VOID); +VOID OsSchedLimitFree(UINTPTR limit); +VOID OsSchedLimitCopy(UINTPTR dest, UINTPTR src); +VOID OsSchedLimitMigrate(UINTPTR currLimit, UINTPTR parentLimit, UINTPTR process); +VOID OsSchedLimitUpdateRuntime(LosTaskCB *runTask, UINT64 currTime, INT32 incTime); +UINT32 OsSchedLimitSetPeriod(ProcSchedLimiter *schedLimit, UINT64 value); +UINT32 OsSchedLimitSetQuota(ProcSchedLimiter *schedLimit, UINT64 value); +BOOL OsSchedLimitCheckTime(LosTaskCB *task); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _LOS_SCHEDLIMIT_H */ diff --git a/syscall/process_syscall.c b/syscall/process_syscall.c index 491f608f38e12ef79f1191f4e4f5c2c0d0bd1648..23857e8a3f24f229bcd81b8b8b7055bab54b8c2a 100644 --- a/syscall/process_syscall.c +++ b/syscall/process_syscall.c @@ -156,6 +156,12 @@ int SysSchedSetScheduler(int id, int policy, int prio, int flag) id = (int)LOS_GetCurrProcessID(); } +#ifdef LOSCFG_KERNEL_PLIMITS + if (prio < OsPidLimitGetPriorityLimit()) { + return -EINVAL; + } +#endif + ret = OsPermissionToCheck(id, LOS_GetCurrProcessID()); if (ret < 0) { return ret; @@ -210,6 +216,12 @@ int SysSetProcessPriority(int which, int who, unsigned int prio) who = (int)LOS_GetCurrProcessID(); } +#ifdef LOSCFG_KERNEL_PLIMITS + if (prio < OsPidLimitGetPriorityLimit()) { + return -EINVAL; + } +#endif + ret = OsPermissionToCheck(who, LOS_GetCurrProcessID()); if (ret < 0) { return ret; @@ -224,6 +236,12 @@ int SysSchedSetParam(int id, unsigned int prio, int flag) return -OsUserTaskSchedulerSet(id, LOS_SCHED_RR, prio, false); } +#ifdef LOSCFG_KERNEL_PLIMITS + if (prio < OsPidLimitGetPriorityLimit()) { + return -EINVAL; + } +#endif + return SysSetProcessPriority(LOS_PRIO_PROCESS, id, prio); } diff --git a/tools/build/mk/los_config.mk b/tools/build/mk/los_config.mk index d404f1378a7348d17cd180f35805d9876dbe43ed..82b45972a9697737cbe09c57779007ddf0f94dc3 100644 --- a/tools/build/mk/los_config.mk +++ b/tools/build/mk/los_config.mk @@ -194,6 +194,13 @@ ifeq ($(LOSCFG_KERNEL_SYSCALL), y) LITEOS_BASELIB += -lsyscall LIB_SUBDIRS += syscall endif + +ifeq ($(LOSCFG_KERNEL_PLIMITS), y) + LITEOS_BASELIB += -lplimit + LIB_SUBDIRS += kernel/extended/plimit + LITEOS_PLIMITS_INCLUDE = -I $(LITEOSTOPDIR)/kernel/extended/plimit +endif + LIB_SUBDIRS += kernel/user ################################### Kernel Option End ################################ @@ -517,7 +524,7 @@ LITEOS_EXTKERNEL_INCLUDE := $(LITEOS_CPPSUPPORT_INCLUDE) $(LITEOS_DYNLOAD_INCL $(LITEOS_VDSO_INCLUDE) $(LITEOS_LITEIPC_INCLUDE) \ $(LITEOS_PIPE_INCLUDE) $(LITEOS_CPUP_INCLUDE) \ $(LITEOS_PERF_INCLUDE) $(LITEOS_LMS_INCLUDE) \ - $(LITEOS_PM_INCLUDE) + $(LITEOS_PM_INCLUDE) $(LITEOS_PLIMITS_INCLUDE) LITEOS_COMPAT_INCLUDE := $(LITEOS_POSIX_INCLUDE) $(LITEOS_LINUX_INCLUDE) \ $(LITEOS_BSD_INCLUDE) LITEOS_FS_INCLUDE := $(LITEOS_VFS_INCLUDE) $(LITEOS_FAT_CACHE_INCLUDE) \