diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c index 30b0f074c0..de47d7b006 100644 --- a/fs/procfs/fs_procfs.c +++ b/fs/procfs/fs_procfs.c @@ -68,6 +68,7 @@ extern const struct procfs_operations cpuload_operations; extern const struct procfs_operations critmon_operations; extern const struct procfs_operations meminfo_operations; extern const struct procfs_operations memdump_operations; +extern const struct procfs_operations mempool_operations; extern const struct procfs_operations iobinfo_operations; extern const struct procfs_operations module_operations; extern const struct procfs_operations uptime_operations; @@ -122,6 +123,10 @@ static const struct procfs_entry_s g_procfs_entries[] = #endif #endif +#if defined(CONFIG_MM_MEMPOOL) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL) + { "mempool", &mempool_operations, PROCFS_FILE_TYPE }, +#endif + #if defined(CONFIG_MM_IOB) && !defined(CONFIG_FS_PROCFS_EXCLUDE_IOBINFO) { "iobinfo", &iobinfo_operations, PROCFS_FILE_TYPE }, #endif diff --git a/include/nuttx/mm/mempool.h b/include/nuttx/mm/mempool.h index 6075f324d3..fed167442a 100644 --- a/include/nuttx/mm/mempool.h +++ b/include/nuttx/mm/mempool.h @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -35,10 +36,22 @@ * Public Types ****************************************************************************/ +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL +struct mempool_procfs_entry_s +{ + FAR const char *name; + FAR struct mempool_procfs_entry_s *next; +}; +#endif + /* This structure describes memory buffer pool */ struct mempool_s { +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL + struct mempool_procfs_entry_s procfs; /* The entry of procfs */ +#endif + sq_queue_t list; /* The free block list in normal mempool */ sq_queue_t ilist; /* The free block list in interrupt mempool */ sq_queue_t elist; /* The expand block list for normal mempool */ @@ -50,6 +63,16 @@ struct mempool_s sem_t wait; /* The semaphore of waiter get free block */ }; +struct mempoolinfo_s +{ + unsigned long arena; /* This is the total size of mempool */ + unsigned long ordblks; /* This is the number of free blocks for normal mempool */ + unsigned long iordblks; /* This is the number of free blocks for interrupt mempool */ + unsigned long aordblks; /* This is the number of used blocks */ + unsigned long sizeblks; /* This is the size of a mempool blocks */ + unsigned long nwaiter; /* This is the number of waiter for mempool */ +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -71,6 +94,7 @@ extern "C" * * Input Parameters: * pool - Address of the memory pool to be used. + * name - The name of memory pool. * bsize - The block size of memory blocks in pool. * ninitial - The initial count of memory blocks in pool. * nexpand - The increment count of memory blocks in pool. @@ -84,8 +108,9 @@ extern "C" * ****************************************************************************/ -int mempool_init(FAR struct mempool_s *pool, size_t bsize, size_t ninitial, - size_t nexpand, size_t ninterrupt); +int mempool_init(FAR struct mempool_s *pool, FAR const char *name, + size_t bsize, size_t ninitial, size_t nexpand, + size_t ninterrupt); /**************************************************************************** * Name: mempool_alloc @@ -119,6 +144,22 @@ FAR void *mempool_alloc(FAR struct mempool_s *pool); void mempool_free(FAR struct mempool_s *pool, FAR void *blk); +/**************************************************************************** + * Name: mempool_info + * + * Description: + * mempool_info returns a copy of updated current mempool information. + * + * Input Parameters: + * pool - Address of the memory pool to be used. + * info - The pointer of mempoolinfo. + * + * Returned Value: + * OK on success; A negated errno value on any failure. + ****************************************************************************/ + +int mempool_info(FAR struct mempool_s *pool, FAR struct mempoolinfo_s *info); + /**************************************************************************** * Name: mempool_deinit * @@ -131,6 +172,38 @@ void mempool_free(FAR struct mempool_s *pool, FAR void *blk); int mempool_deinit(FAR struct mempool_s *pool); +/**************************************************************************** + * Name: mempool_procfs_register + * + * Description: + * Add a new mempool entry to the procfs file system. + * + * Input Parameters: + * entry - Describes the entry to be registered. + * name - The name of mempool. + * + ****************************************************************************/ + +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL +void mempool_procfs_register(FAR struct mempool_procfs_entry_s *entry, + FAR const char *name); +#endif + +/**************************************************************************** + * Name: mempool_procfs_unregister + * + * Description: + * Remove a mempool entry from the procfs file system. + * + * Input Parameters: + * entry - Describes the entry to be unregistered. + * + ****************************************************************************/ + +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL +void mempool_procfs_unregister(FAR struct mempool_procfs_entry_s *entry); +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/mm/Kconfig b/mm/Kconfig index c8c6df5f65..2ab31daa70 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -178,6 +178,11 @@ config MM_MEMPOOL Memory buffer pool support. Such pools are mostly used for guaranteed, deadlock-free memory allocations. +config FS_PROCFS_EXCLUDE_MEMPOOL + bool "Exclude mempool" + default n + depends on FS_PROCFS + config MM_KASAN bool "Kernel Address Sanitizer" default n diff --git a/mm/mempool/Make.defs b/mm/mempool/Make.defs index cda9195fed..6f3dca5479 100644 --- a/mm/mempool/Make.defs +++ b/mm/mempool/Make.defs @@ -21,8 +21,19 @@ # Memory buffer pool management ifeq ($(CONFIG_MM_MEMPOOL),y) + CSRCS += mempool.c +ifeq ($(CONFIG_FS_PROCFS),y) + +ifneq ($(CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL),y) + +CSRCS += mempool_procfs.c + +endif + +endif + # Add the memory buffer pool directory to the build DEPPATH += --dep-path mempool diff --git a/mm/mempool/mempool.c b/mm/mempool/mempool.c index 5076556518..40057c6aff 100644 --- a/mm/mempool/mempool.c +++ b/mm/mempool/mempool.c @@ -53,6 +53,7 @@ static inline void mempool_add_list(FAR sq_queue_t *list, FAR void *base, * * Input Parameters: * pool - Address of the memory pool to be used. + * name - The name of memory pool. * bsize - The block size of memory blocks in pool. * ninitial - The initial count of memory blocks in pool. * nexpand - The increment count of memory blocks in pool. @@ -66,8 +67,9 @@ static inline void mempool_add_list(FAR sq_queue_t *list, FAR void *base, * ****************************************************************************/ -int mempool_init(FAR struct mempool_s *pool, size_t bsize, size_t ninitial, - size_t nexpand, size_t ninterrupt) +int mempool_init(FAR struct mempool_s *pool, FAR const char *name, + size_t bsize, size_t ninitial, size_t nexpand, + size_t ninterrupt) { size_t count = ninitial + ninterrupt; @@ -102,6 +104,10 @@ int mempool_init(FAR struct mempool_s *pool, size_t bsize, size_t ninitial, nxsem_init(&pool->wait, 0, 0); nxsem_set_protocol(&pool->wait, SEM_PRIO_NONE); +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL + mempool_procfs_register(&pool->procfs, name); +#endif + return 0; } @@ -227,6 +233,51 @@ void mempool_free(FAR struct mempool_s *pool, FAR void *blk) } } +/**************************************************************************** + * Name: mempool_info + * + * Description: + * mempool_info returns a copy of updated current mempool information. + * + * Input Parameters: + * pool - Address of the memory pool to be used. + * info - The pointer of mempoolinfo. + * + * Returned Value: + * OK on success; A negated errno value on any failure. + ****************************************************************************/ + +int mempool_info(FAR struct mempool_s *pool, FAR struct mempoolinfo_s *info) +{ + irqstate_t flags; + + if (pool == NULL || info == NULL) + { + return -EINVAL; + } + + flags = spin_lock_irqsave(&pool->lock); + info->ordblks = sq_count(&pool->list); + info->iordblks = sq_count(&pool->ilist); + info->aordblks = pool->nused; + info->arena = (pool->nused + info->ordblks + info->iordblks) * pool->bsize; + spin_unlock_irqrestore(&pool->lock, flags); + info->sizeblks = pool->bsize; + if (pool->nexpand == 0) + { + int semcount; + + nxsem_get_value(&pool->wait, &semcount); + info->nwaiter = -semcount; + } + else + { + info->nwaiter = 0; + } + + return 0; +} + /**************************************************************************** * Name: mempool_deinit * @@ -251,6 +302,10 @@ int mempool_deinit(FAR struct mempool_s *pool) return -EBUSY; } +#ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMPOOL + mempool_procfs_unregister(&pool->procfs); +#endif + while ((blk = sq_remfirst(&pool->elist)) != NULL) { kmm_free(blk); diff --git a/mm/mempool/mempool_procfs.c b/mm/mempool/mempool_procfs.c new file mode 100644 index 0000000000..df9bc917a0 --- /dev/null +++ b/mm/mempool/mempool_procfs.c @@ -0,0 +1,260 @@ +/**************************************************************************** + * mm/mempool/mempool_procfs.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Determines the size of an intermediate buffer that must be large enough + * to handle the longest line generated by this logic. + */ + +#define MEMPOOLINFO_LINELEN 80 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one open "file" */ + +struct mempool_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + unsigned int linesize; /* Number of valid characters in line[] */ + char line[MEMPOOLINFO_LINELEN]; /* Pre-allocated buffer for formatted lines */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int mempool_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode); +static int mempool_close(FAR struct file *filep); +static int mempool_dup(FAR const struct file *oldp, + FAR struct file *newp); +static int mempool_stat(FAR const char *relpath, FAR struct stat *buf); +static ssize_t mempool_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct procfs_operations mempool_operations = +{ + mempool_open, /* open */ + mempool_close, /* close */ + mempool_read, /* read */ + NULL, /* write */ + mempool_dup, /* dup */ + NULL, /* opendir */ + NULL, /* closedir */ + NULL, /* readdir */ + NULL, /* rewinddir */ + mempool_stat /* stat */ +}; + +static FAR struct mempool_procfs_entry_s *g_mempool_procfs = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mempool_open + ****************************************************************************/ + +static int mempool_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode) +{ + FAR struct mempool_file_s *procfile; + + procfile = kmm_zalloc(sizeof(struct mempool_file_s)); + if (procfile == NULL) + { + return -ENOMEM; + } + + filep->f_priv = procfile; + return 0; +} + +/**************************************************************************** + * Name: mempool_close + ****************************************************************************/ + +static int mempool_close(FAR struct file *filep) +{ + kmm_free(filep->f_priv); + filep->f_priv = NULL; + return 0; +} + +/**************************************************************************** + * Name: mempool_read + ****************************************************************************/ + +static ssize_t mempool_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR const struct mempool_procfs_entry_s *entry; + FAR struct mempool_file_s *procfile; + size_t linesize; + size_t copysize; + size_t totalsize; + off_t offset; + + offset = filep->f_pos; + procfile = filep->f_priv; + linesize = procfs_snprintf(procfile->line, MEMPOOLINFO_LINELEN, + "%13s%11s%9s%9s%9s%9s%9s\n", "", "total", + "bsize", "nused", "nfree", "nifree", + "nwaiter"); + + copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen, + &offset); + totalsize = copysize; + + for (entry = g_mempool_procfs; entry != NULL; entry = entry->next) + { + if (totalsize < buflen) + { + struct mempoolinfo_s minfo; + + buffer += copysize; + buflen -= copysize; + + mempool_info((FAR struct mempool_s *)entry, &minfo); + linesize = procfs_snprintf(procfile->line, MEMPOOLINFO_LINELEN, + "%12s:%11lu%9lu%9lu%9lu%9lu%9lu\n", + entry->name, minfo.arena, + minfo.sizeblks, minfo.aordblks, + minfo.ordblks, minfo.iordblks, + minfo.nwaiter); + copysize = procfs_memcpy(procfile->line, linesize, buffer, + buflen, &offset); + totalsize += copysize; + } + } + + filep->f_pos += totalsize; + return totalsize; +} + +/**************************************************************************** + * Name: mempool_dup + * + * Description: + * Duplicate open file data in the new file structure. + * + ****************************************************************************/ + +static int mempool_dup(FAR const struct file *oldp, FAR struct file *newp) +{ + FAR struct mempool_file_s *oldattr; + FAR struct mempool_file_s *newattr; + + oldattr = oldp->f_priv; + newattr = kmm_malloc(sizeof(struct mempool_file_s)); + if (newattr == NULL) + { + return -ENOMEM; + } + + memcpy(newattr, oldattr, sizeof(struct mempool_file_s)); + newp->f_priv = newattr; + return 0; +} + +/**************************************************************************** + * Name: mempool_stat + * + * Description: Return information about a file or directory + * + ****************************************************************************/ + +static int mempool_stat(FAR const char *relpath, FAR struct stat *buf) +{ + memset(buf, 0, sizeof(struct stat)); + buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR; + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mempool_procfs_register + * + * Description: + * Add a new mempool entry to the procfs file system. + * + * Input Parameters: + * entry - Describes the entry to be registered. + * + ****************************************************************************/ + +void mempool_procfs_register(FAR struct mempool_procfs_entry_s *entry, + FAR const char *name) +{ + entry->name = name; + entry->next = g_mempool_procfs; + g_mempool_procfs = entry; +} + +/**************************************************************************** + * Name: mempool_procfs_unregister + * + * Description: + * Remove a mempool entry from the procfs file system. + * + * Input Parameters: + * entry - Describes the entry to be unregistered. + * + ****************************************************************************/ + +void mempool_procfs_unregister(FAR struct mempool_procfs_entry_s *entry) +{ + FAR struct mempool_procfs_entry_s **cur; + + for (cur = &g_mempool_procfs; *cur != NULL; cur = &(*cur)->next) + { + if (*cur == entry) + { + *cur = entry->next; + break; + } + } +}