openharmony_kernel_liteos_a/fs/proc/os_adapt/plimits_proc.c

906 lines
27 KiB
C

/*
* 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 <sys/statfs.h>
#include <stdio.h>
#include <unistd.h>
#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 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.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;
}
#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) || (value > (long long int)OS_NULL_INT)) {
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) || (value > (long long int)OS_NULL_INT)) {
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