OS modules: Add basic procfs support. A module registry that will eventually be used to support lsmod

This commit is contained in:
Gregory Nutt 2015-12-12 17:42:25 -06:00
parent a908a61c5a
commit 795ddd7e80
15 changed files with 910 additions and 92 deletions

View File

@ -11237,5 +11237,6 @@
just the ELF module support with name changes (2015-12-10).
* configs/samv71-xult/module: Add configuration for testing OS
modules (2015-12-12).
* sched/module: Add an implementation of rmmod() (2015-11-12).
* sched/module: Add an implementation of rmmod() (2015-12-12).
* sched/module and fs/procfs: Add some basic module procfs support
(2015-12-12),

@ -1 +1 @@
Subproject commit 050dca048e92cec8f8d04075553d75025a31f2d4
Subproject commit 4a56b7ba643607bbfadaef3628a7322b642ffa3f

View File

@ -32,6 +32,13 @@ config FS_PROCFS_EXCLUDE_PROCESS
This will reduce code space, but then giving access to process info
was kinda the whole point of procfs, but hey, whatever.
config FS_PROCFS_EXCLUDE_MODULE
bool "Exclude module information"
depends on MODULE
default n
---help---
Causes the module information to be excluded from the procfs system.
config FS_PROCFS_EXCLUDE_UPTIME
bool "Exclude uptime"
default n

View File

@ -77,6 +77,7 @@
extern const struct procfs_operations proc_operations;
extern const struct procfs_operations cpuload_operations;
extern const struct procfs_operations module_operations;
extern const struct procfs_operations uptime_operations;
/* This is not good. These are implemented in other sub-systems. Having to
@ -119,6 +120,10 @@ static const struct procfs_entry_s g_procfs_entries[] =
{ "cpuload", &cpuload_operations },
#endif
#if defined(CONFIG_MODULE) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
{ "modules", &module_operations },
#endif
#if defined(CONFIG_FS_SMARTFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)
//{ "fs/smartfs", &smartfs_procfsoperations },
{ "fs/smartfs**", &smartfs_procfsoperations },

View File

@ -60,10 +60,6 @@
# define CONFIG_MODULE_ALIGN_LOG2 2
#endif
#ifndef CONFIG_MODULE_STACKSIZE
# define CONFIG_MODULE_STACKSIZE 2048
#endif
#ifndef CONFIG_MODULE_BUFFERSIZE
# define CONFIG_MODULE_BUFFERSIZE 128
#endif
@ -72,6 +68,8 @@
# define CONFIG_MODULE_BUFFERINCR 32
#endif
#define MODULENAME_MAX 16
/****************************************************************************
* Public Types
****************************************************************************/
@ -114,25 +112,12 @@ typedef CODE int (*mod_uninitializer_t)(FAR void *arg);
typedef CODE int (*mod_initializer_t)(mod_uninitializer_t *uninitializer,
FAR void **arg);
/* This describes the file to be loaded. */
#ifdef __KERNEL__
/* This is the type of the callback function used by mod_registry_foreach() */
struct symtab_s;
struct module_s
{
/* Information provided to insmod by the caller */
FAR const char *filename; /* Full path to the binary to be loaded */
FAR const struct symtab_s *exports; /* Table of exported symbols */
int nexports; /* The number of symbols in exports[] */
/* Information provided from insmod (if successful) describing the
* resources used by the loaded module.
*/
mod_uninitializer_t uninitializer; /* Module uninitializer function */
FAR void *arg; /* Uninitializer argument */
FAR void *alloc; /* Allocated kernel memory */
};
struct module_s;
typedef CODE int (*mod_callback_t)(FAR struct module_s *modp, FAR void *arg);
#endif
/****************************************************************************
* Public Function Prototypes
@ -154,9 +139,22 @@ extern "C"
* Verify that the file is an ELF module binary and, if so, load the
* module into kernel memory and initialize it for use.
*
* Input Parameters:
*
* filename - Full path to the module binary to be loaded
* modulename - The name that can be used to refer to the module after
* it has been loaded.
* exports - Table of exported symbols
* nexports - The number of symbols in exports[]
*
* Returned Value:
* Zero (OK) on success. On any failure, -1 (ERROR) is returned the
* errno value is set appropriately.
*
****************************************************************************/
int insmod(FAR struct module_s *modp);
int insmod(FAR const char *filename, FAR const char *modulename,
FAR const struct symtab_s *exports, int nexports);
/****************************************************************************
* Name: rmmod
@ -164,9 +162,44 @@ int insmod(FAR struct module_s *modp);
* Description:
* Remove a previously installed module from memory.
*
* Input Parameters:
*
* modulename - The module name. This is the name module name that was
* provided to insmod when the module was loaded.
*
* Returned Value:
* Zero (OK) on success. On any failure, -1 (ERROR) is returned the
* errno value is set appropriately.
*
****************************************************************************/
int rmmod(FAR struct module_s *modp);
int rmmod(FAR const char *modulename);
/****************************************************************************
* Name: mod_registry_foreach
*
* Description:
* Visit each module in the registry. This is an internal OS interface and
* not available for use by applications.
*
* Input Parameters:
* callback - This callback function was be called for each entry in the
* registry.
* arg - This opaque argument will be passed to the callback function.
*
* Returned Value:
* This function normally returns zero (OK). If, however, any callback
* function returns a non-zero value, the traversal will be terminated and
* that non-zero value will be returned.
*
* Assumptions:
* The caller does NOT hold the lock on the module registry.
*
****************************************************************************/
#ifdef __KERNEL__
int mod_registry_foreach(mod_callback_t callback, FAR void *arg);
#endif
#undef EXTERN
#if defined(__cplusplus)

View File

@ -60,10 +60,6 @@
* Public Type Definitions
****************************************************************************/
/* This enumeration identifies all of the thread attributes that can be
* accessed via the procfs file system.
*/
/* This structure describes one open "file" */
struct net_driver_s; /* Forward reference */

View File

@ -42,8 +42,16 @@ CSRCS += mod_insmod.c mod_rmmod.c
# loadable module library
CSRCS += mod_bind.c mod_init.c mod_iobuffer.c mod_load.c mod_read.c
CSRCS += mod_sections.c mod_symbols.c mod_uninit.c mod_unload.c
CSRCS += mod_verify.c
CSRCS += mod_registry.c mod_sections.c mod_symbols.c mod_uninit.c
CSRCS += mod_unload.c mod_verify.c
# procfs support
ifeq ($(CONFIG_FS_PROCFS),y)
ifneq ($(CONFIG_FS_PROCFS_EXCLUDE_MODULE),y)
CSRCS += mod_procfs.c
endif
endif
# Hook the module subdirectory into the build

View File

@ -47,6 +47,7 @@
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/module.h>
#include "module/module.h"
@ -66,7 +67,7 @@
#endif
#ifdef CONFIG_MODULE_DUMPBUFFER
# define mod_dumpbuffer(m,b,n) bvdbgdumpbuffer(m,b,n)
# define mod_dumpbuffer(m,b,n) svdbgdumpbuffer(m,b,n)
#else
# define mod_dumpbuffer(m,b,n)
#endif
@ -88,50 +89,50 @@ static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo)
{
int i;
bdbg("LOAD_INFO:\n");
bdbg(" textalloc: %08lx\n", (long)loadinfo->textalloc);
bdbg(" datastart: %08lx\n", (long)loadinfo->datastart);
bdbg(" textsize: %ld\n", (long)loadinfo->textsize);
bdbg(" datasize: %ld\n", (long)loadinfo->datasize);
bdbg(" filelen: %ld\n", (long)loadinfo->filelen);
bdbg(" filfd: %d\n", loadinfo->filfd);
bdbg(" symtabidx: %d\n", loadinfo->symtabidx);
bdbg(" strtabidx: %d\n", loadinfo->strtabidx);
sdbg("LOAD_INFO:\n");
sdbg(" textalloc: %08lx\n", (long)loadinfo->textalloc);
sdbg(" datastart: %08lx\n", (long)loadinfo->datastart);
sdbg(" textsize: %ld\n", (long)loadinfo->textsize);
sdbg(" datasize: %ld\n", (long)loadinfo->datasize);
sdbg(" filelen: %ld\n", (long)loadinfo->filelen);
sdbg(" filfd: %d\n", loadinfo->filfd);
sdbg(" symtabidx: %d\n", loadinfo->symtabidx);
sdbg(" strtabidx: %d\n", loadinfo->strtabidx);
bdbg("ELF Header:\n");
bdbg(" e_ident: %02x %02x %02x %02x\n",
sdbg("ELF Header:\n");
sdbg(" e_ident: %02x %02x %02x %02x\n",
loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1],
loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]);
bdbg(" e_type: %04x\n", loadinfo->ehdr.e_type);
bdbg(" e_machine: %04x\n", loadinfo->ehdr.e_machine);
bdbg(" e_version: %08x\n", loadinfo->ehdr.e_version);
bdbg(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry);
bdbg(" e_phoff: %d\n", loadinfo->ehdr.e_phoff);
bdbg(" e_shoff: %d\n", loadinfo->ehdr.e_shoff);
bdbg(" e_flags: %08x\n" , loadinfo->ehdr.e_flags);
bdbg(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize);
bdbg(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize);
bdbg(" e_phnum: %d\n", loadinfo->ehdr.e_phnum);
bdbg(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize);
bdbg(" e_shnum: %d\n", loadinfo->ehdr.e_shnum);
bdbg(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx);
sdbg(" e_type: %04x\n", loadinfo->ehdr.e_type);
sdbg(" e_machine: %04x\n", loadinfo->ehdr.e_machine);
sdbg(" e_version: %08x\n", loadinfo->ehdr.e_version);
sdbg(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry);
sdbg(" e_phoff: %d\n", loadinfo->ehdr.e_phoff);
sdbg(" e_shoff: %d\n", loadinfo->ehdr.e_shoff);
sdbg(" e_flags: %08x\n" , loadinfo->ehdr.e_flags);
sdbg(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize);
sdbg(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize);
sdbg(" e_phnum: %d\n", loadinfo->ehdr.e_phnum);
sdbg(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize);
sdbg(" e_shnum: %d\n", loadinfo->ehdr.e_shnum);
sdbg(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx);
if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0)
{
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
{
FAR Elf32_Shdr *shdr = &loadinfo->shdr[i];
bdbg("Sections %d:\n", i);
bdbg(" sh_name: %08x\n", shdr->sh_name);
bdbg(" sh_type: %08x\n", shdr->sh_type);
bdbg(" sh_flags: %08x\n", shdr->sh_flags);
bdbg(" sh_addr: %08x\n", shdr->sh_addr);
bdbg(" sh_offset: %d\n", shdr->sh_offset);
bdbg(" sh_size: %d\n", shdr->sh_size);
bdbg(" sh_link: %d\n", shdr->sh_link);
bdbg(" sh_info: %d\n", shdr->sh_info);
bdbg(" sh_addralign: %d\n", shdr->sh_addralign);
bdbg(" sh_entsize: %d\n", shdr->sh_entsize);
sdbg("Sections %d:\n", i);
sdbg(" sh_name: %08x\n", shdr->sh_name);
sdbg(" sh_type: %08x\n", shdr->sh_type);
sdbg(" sh_flags: %08x\n", shdr->sh_flags);
sdbg(" sh_addr: %08x\n", shdr->sh_addr);
sdbg(" sh_offset: %d\n", shdr->sh_offset);
sdbg(" sh_size: %d\n", shdr->sh_size);
sdbg(" sh_link: %d\n", shdr->sh_link);
sdbg(" sh_info: %d\n", shdr->sh_info);
sdbg(" sh_addralign: %d\n", shdr->sh_addralign);
sdbg(" sh_entsize: %d\n", shdr->sh_entsize);
}
}
}
@ -165,49 +166,90 @@ static void mod_dumpinitializer(mod_initializer_t initializer,
* Verify that the file is an ELF module binary and, if so, load the
* module into kernel memory and initialize it for use.
*
* Input Parameters:
*
* filename - Full path to the module binary to be loaded
* modulename - The name that can be used to refer to the module after
* it has been loaded.
* exports - Table of exported symbols
* nexports - The number of symbols in exports[]
*
* Returned Value:
* Zero (OK) on success. On any failure, -1 (ERROR) is returned the
* errno value is set appropriately.
*
****************************************************************************/
int insmod(FAR struct module_s *modp)
int insmod(FAR const char *filename, FAR const char *modulename,
FAR const struct symtab_s *exports, int nexports)
{
struct mod_loadinfo_s loadinfo;
FAR struct module_s *modp;
mod_initializer_t initializer;
int ret;
DEBUGASSERT(modp != NULL && modp->filename != NULL);
bvdbg("Loading file: %s\n", modp->filename);
DEBUGASSERT(filename != NULL && modulename != NULL);
svdbg("Loading file: %s\n", filename);
/* Get exclusive access to the module registry */
mod_registry_lock();
/* Check if this module is already installed */
if (mod_registry_find(modulename) != NULL)
{
mod_registry_unlock();
ret = -EEXIST;
goto errout_with_lock;
}
/* Initialize the ELF library to load the program binary. */
ret = mod_initialize(modp->filename, &loadinfo);
ret = mod_initialize(filename, &loadinfo);
mod_dumploadinfo(&loadinfo);
if (ret != 0)
{
bdbg("Failed to initialize for load of ELF program: %d\n", ret);
goto errout;
sdbg("ERROR: Failed to initialize to load module: %d\n", ret);
goto errout_with_lock;
}
/* Allocate a module registry entry to hold the module data */
modp = (FAR struct module_s *)kmm_zalloc(sizeof(struct module_s));
if (ret != 0)
{
sdbg("Failed to initialize for load of ELF program: %d\n", ret);
goto errout_with_loadinfo;
}
/* Save the module name in the registry entry */
strncpy(modp->modulename, modulename, MODULENAME_MAX);
/* Load the program binary */
ret = mod_load(&loadinfo);
mod_dumploadinfo(&loadinfo);
if (ret != 0)
{
bdbg("Failed to load ELF program binary: %d\n", ret);
goto errout_with_init;
sdbg("Failed to load ELF program binary: %d\n", ret);
goto errout_with_registry_entry;
}
/* Bind the program to the exported symbol table */
ret = mod_bind(&loadinfo, modp->exports, modp->nexports);
ret = mod_bind(&loadinfo, exports, nexports);
if (ret != 0)
{
bdbg("Failed to bind symbols program binary: %d\n", ret);
sdbg("Failed to bind symbols program binary: %d\n", ret);
goto errout_with_load;
}
/* Return the load information */
modp->alloc = (FAR void *)loadinfo.textalloc;
modp->size = loadinfo.textsize + loadinfo.datasize;
/* Get the module initializer entry point */
@ -219,19 +261,28 @@ int insmod(FAR struct module_s *modp)
ret = initializer(&modp->uninitializer, &modp->arg);
if (ret < 0)
{
bdbg("Failed to initialize the module: %d\n", ret);
sdbg("Failed to initialize the module: %d\n", ret);
goto errout_with_load;
}
/* Add the new module entry to the registry */
mod_registry_add(modp);
mod_uninitialize(&loadinfo);
mod_registry_unlock();
return OK;
errout_with_load:
mod_unload(&loadinfo);
errout_with_init:
errout_with_registry_entry:
kmm_free(modp);
errout_with_loadinfo:
mod_uninitialize(&loadinfo);
errout:
return ret;
errout_with_lock:
mod_registry_unlock();
set_errno(-ret);
return ERROR;
}
#endif /* CONFIG_MODULE */

320
sched/module/mod_procfs.c Normal file
View File

@ -0,0 +1,320 @@
/****************************************************************************
* sched/module/mod_procfs.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 NuttX 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 OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/module.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/procfs.h>
#include "module.h"
#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_PROCFS) && \
!defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
/****************************************************************************
* 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 MOD_LINELEN 64
/****************************************************************************
* Private Types
****************************************************************************/
/* This structure describes one open "file" */
struct modprocfs_file_s
{
struct procfs_file_s base; /* Base open file structure */
/* Read helpers */
FAR char *buffer; /* User buffer pointer */
size_t buflen; /* Size of the user buffer */
size_t remaining; /* Space remaining in user buffer */
size_t totalsize; /* Total size returned by read() */
off_t offset; /* Offset skip on output */
/* Line buffer */
uint8_t lineno; /* Line number */
uint8_t linesize; /* Number of valid characters in line[] */
char line[MOD_LINELEN]; /* Pre-allocated buffer for formatted lines */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* File system methods */
static int modprocfs_open(FAR struct file *filep, FAR const char *relpath,
int oflags, mode_t mode);
static int modprocfs_close(FAR struct file *filep);
static ssize_t modprocfs_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static int modprocfs_dup(FAR const struct file *oldp,
FAR struct file *newp);
static int modprocfs_stat(FAR const char *relpath, FAR struct stat *buf);
/****************************************************************************
* Public Data
****************************************************************************/
/* See include/nutts/fs/procfs.h
* We use the old-fashioned kind of initializers so that this will compile
* with any compiler.
*/
const struct procfs_operations module_operations =
{
modprocfs_open, /* open */
modprocfs_close, /* close */
modprocfs_read, /* read */
NULL, /* write */
modprocfs_dup, /* dup */
NULL, /* opendir */
NULL, /* closedir */
NULL, /* readdir */
NULL, /* rewinddir */
modprocfs_stat /* stat */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: modprocfs_callback
****************************************************************************/
static int modprocfs_callback(FAR struct module_s *modp, FAR void *arg)
{
FAR struct modprocfs_file_s *priv;
size_t linesize;
size_t copysize;
DEBUGASSERT(modp != NULL && arg != NULL);
priv = (FAR struct modprocfs_file_s *)arg;
linesize = snprintf(priv->line, MOD_LINELEN, "%s,%p,%p,%p,%lu\n",
modp->modulename, modp->uninitializer, modp->arg,
modp->alloc, (unsigned long)modp->size);
copysize = procfs_memcpy(priv->line, linesize, priv->buffer,
priv->remaining, &priv->offset);
priv->totalsize += copysize;
priv->buffer += copysize;
priv->remaining -= copysize;
return (priv->totalsize >= priv->buflen) ? 1 : 0;
}
/****************************************************************************
* Name: modprocfs_open
****************************************************************************/
static int modprocfs_open(FAR struct file *filep, FAR const char *relpath,
int oflags, mode_t mode)
{
FAR struct modprocfs_file_s *priv;
fvdbg("Open '%s'\n", relpath);
/* PROCFS is read-only. Any attempt to open with any kind of write
* access is not permitted.
*
* REVISIT: Write-able proc files could be quite useful.
*/
if (((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0))
{
fdbg("ERROR: Only O_RDONLY supported\n");
return -EACCES;
}
/* Allocate the open file structure */
priv = (FAR struct modprocfs_file_s *)kmm_zalloc(sizeof(struct modprocfs_file_s));
if (!priv)
{
fdbg("ERROR: Failed to allocate file attributes\n");
return -ENOMEM;
}
/* Save the open file structure as the open-specific state in
* filep->f_priv.
*/
filep->f_priv = (FAR void *)priv;
return OK;
}
/****************************************************************************
* Name: modprocfs_close
****************************************************************************/
static int modprocfs_close(FAR struct file *filep)
{
FAR struct modprocfs_file_s *priv;
/* Recover our private data from the struct file instance */
priv = (FAR struct modprocfs_file_s *)filep->f_priv;
DEBUGASSERT(priv);
/* Release the file attributes structure */
kmm_free(priv);
filep->f_priv = NULL;
return OK;
}
/****************************************************************************
* Name: modprocfs_read
****************************************************************************/
static ssize_t modprocfs_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR struct modprocfs_file_s *priv;
int ret;
fvdbg("buffer=%p buflen=%lu\n", buffer, (unsigned long)buflen);
/* Recover our private data from the struct file instance */
priv = (FAR struct modprocfs_file_s *)filep->f_priv;
DEBUGASSERT(priv);
/* Traverse all installed modules */
priv->remaining = buflen;
priv->totalsize = 0;
priv->buffer = buffer;
priv->buflen = buflen;
priv->offset = filep->f_pos;
ret = mod_registry_foreach(modprocfs_callback, priv);
if (ret >= 0)
{
filep->f_pos += priv->totalsize;
return priv->totalsize;
}
return ret;
}
/****************************************************************************
* Name: modprocfs_dup
*
* Description:
* Duplicate open file data in the new file structure.
*
****************************************************************************/
static int modprocfs_dup(FAR const struct file *oldp, FAR struct file *newp)
{
FAR struct modprocfs_file_s *oldpriv;
FAR struct modprocfs_file_s *newpriv;
fvdbg("Dup %p->%p\n", oldp, newp);
/* Recover our private data from the old struct file instance */
oldpriv = (FAR struct modprocfs_file_s *)oldp->f_priv;
DEBUGASSERT(oldpriv);
/* Allocate a new container to hold the task and attribute selection */
newpriv = (FAR struct modprocfs_file_s *)kmm_zalloc(sizeof(struct modprocfs_file_s));
if (!newpriv)
{
fdbg("ERROR: Failed to allocate file attributes\n");
return -ENOMEM;
}
/* The copy the file attribtes from the old attributes to the new */
memcpy(newpriv, oldpriv, sizeof(struct modprocfs_file_s));
/* Save the new attributes in the new file structure */
newp->f_priv = (FAR void *)newpriv;
return OK;
}
/****************************************************************************
* Name: modprocfs_stat
*
* Description: Return information about a file or directory
*
****************************************************************************/
static int modprocfs_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 OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS &&
* !CONFIG_FS_PROCFS_EXCLUDE_MODULE */

247
sched/module/mod_registry.c Normal file
View File

@ -0,0 +1,247 @@
/****************************************************************************
* sched/module/mod_registry.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 NuttX 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 OWNER 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <string.h>
#include <semaphore.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/module.h>
#include "module.h"
/****************************************************************************
* Private Data
****************************************************************************/
static sem_t g_mod_lock = SEM_INITIALIZER(1);
static FAR struct module_s *g_mod_registry;
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mod_registry_lock
*
* Description:
* Get exclusive access to the module registry.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void mod_registry_lock(void)
{
while (sem_post(&g_mod_lock) < 0)
{
DEBUGASSERT(errno == EINTR);
}
}
/****************************************************************************
* Name: mod_registry_unlock
*
* Description:
* Relinquish the lock on the module registry
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void mod_registry_unlock(void)
{
sem_post(&g_mod_lock);
}
/****************************************************************************
* Name: mod_registry_add
*
* Description:
* Add a new entry to the module registry.
*
* Input Parameters:
* modp - The module data structure to be registered.
*
* Returned Value:
* None
*
* Assumptions:
* The caller holds the lock on the module registry.
*
****************************************************************************/
void mod_registry_add(FAR struct module_s *modp)
{
DEBUGASSERT(modp);
modp->flink = g_mod_registry;
g_mod_registry = modp;
}
/****************************************************************************
* Name: mod_registry_del
*
* Description:
* Remove a module entry from the registry
*
* Input Parameters:
* modp - The registry entry to be removed.
*
* Returned Value:
* Zero (OK) is returned if the registry entry was deleted. Otherwise,
* a negated errno value is returned.
*
* Assumptions:
* The caller holds the lock on the module registry.
*
****************************************************************************/
int mod_registry_del(FAR struct module_s *modp)
{
FAR struct module_s *prev;
FAR struct module_s *curr;
for (prev = NULL, curr = g_mod_registry;
curr != NULL && curr != modp;
prev = curr, curr = curr->flink);
if (curr == NULL)
{
sdbg("ERROR: Could not find module entry\n");
return -ENOENT;
}
if (prev == NULL)
{
g_mod_registry = modp->flink;
}
else
{
prev->flink = modp->flink;
}
modp->flink = NULL;
return OK;
}
/****************************************************************************
* Name: mod_registry_find
*
* Description:
* Find an entry in the module registry using the name of the module.
*
* Input Parameters:
* modulename - The name of the module to be found
*
* Returned Value:
* If the registry entry is found, a pointer to the module entry is
* returned. NULL is returned if the they entry is not found.
*
* Assumptions:
* The caller holds the lock on the module registry.
*
****************************************************************************/
FAR struct module_s *mod_registry_find(FAR const char *modulename)
{
FAR struct module_s *modp;
for (modp = g_mod_registry;
modp != NULL && strncmp(modp->modulename, modulename, MODULENAME_MAX) != 0;
modp = modp->flink);
return modp;
}
/****************************************************************************
* Name: mod_registry_foreach
*
* Description:
* Visit each module in the registry
*
* Input Parameters:
* callback - This callback function was be called for each entry in the
* registry.
* arg - This opaque argument will be passed to the callback function.
*
* Returned Value:
* This function normally returns zero (OK). If, however, any callback
* function returns a non-zero value, the traversal will be terminated and
* that non-zero value will be returned.
*
* Assumptions:
* The caller does *NOT* hold the lock on the module registry.
*
****************************************************************************/
int mod_registry_foreach(mod_callback_t callback, FAR void *arg)
{
FAR struct module_s *modp;
int ret;
/* Get exclusive access to the module registry */
mod_registry_lock();
/* Visit each installed module */
for (modp = g_mod_registry; modp != NULL; modp = modp->flink)
{
/* Perform the callback */
ret = callback(modp, arg);
if (ret != 0)
{
return ret;
}
}
mod_registry_unlock();
return OK;
}

View File

@ -42,6 +42,7 @@
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <nuttx/kmalloc.h>
#include <nuttx/module.h>
@ -60,13 +61,37 @@
* Description:
* Remove a previously installed module from memory.
*
* Input Parameters:
*
* modulename - The module name. This is the name module name that was
* provided to insmod when the module was loaded.
*
* Returned Value:
* Zero (OK) on success. On any failure, -1 (ERROR) is returned the
* errno value is set appropriately.
*
****************************************************************************/
int rmmod(FAR struct module_s *modp)
int rmmod(FAR const char *modulename)
{
FAR struct module_s *modp;
int ret = OK;
DEBUGASSERT(modp != NULL);
DEBUGASSERT(modulename != NULL);
/* Get exclusive access to the module registry */
mod_registry_lock();
/* Find the module entry for this modulename in the registry */
modp = mod_registry_find(modulename);
if (modp == NULL)
{
sdbg("ERROR: Failed to find module %s: %d\n", modulename, ret);
ret = -ENOENT;
goto errout_with_lock;
}
/* Is there an uninitializer? */
@ -81,7 +106,7 @@ int rmmod(FAR struct module_s *modp)
if (ret < 0)
{
sdbg("ERROR: Failed to uninitialize the module: %d\n", ret);
return ret;
goto errout_with_lock;
}
/* Nullify so that the uninitializer cannot be called again */
@ -92,7 +117,7 @@ int rmmod(FAR struct module_s *modp)
/* Release resources held by the module */
if (modp->alloc != 0)
if (modp->alloc != NULL)
{
/* Free the module memory */
@ -101,9 +126,29 @@ int rmmod(FAR struct module_s *modp)
/* Nullify so that the memory cannot be freed again */
modp->alloc = NULL;
modp->size = 0;
}
return ret;
/* Remove the module from the registry */
ret = mod_registry_del(modp);
if (ret < 0)
{
sdbg("ERROR: Failed to remove the module from the registry: %d\n", ret);
goto errout_with_lock;
}
mod_registry_unlock();
/* And free the registry entry */
kmm_free(modp);
return OK;
errout_with_lock:
mod_registry_unlock();
set_errno(-ret);
return ERROR;
}
#endif /* CONFIG_MODULE */

View File

@ -52,6 +52,19 @@
* Public Types
****************************************************************************/
/* This describes the file to be loaded. */
struct symtab_s;
struct module_s
{
FAR struct module_s *flink; /* Supports a singly linked list */
FAR char modulename[MODULENAME_MAX]; /* Module name */
mod_uninitializer_t uninitializer; /* Module uninitializer function */
FAR void *arg; /* Uninitializer argument */
FAR void *alloc; /* Allocated kernel memory */
size_t size; /* Size of the kernel memory allocation */
};
/* This struct provides a description of the currently loaded instantiation
* of the kernel module.
*/
@ -332,4 +345,95 @@ int mod_allocbuffer(FAR struct mod_loadinfo_s *loadinfo);
int mod_reallocbuffer(FAR struct mod_loadinfo_s *loadinfo, size_t increment);
/****************************************************************************
* Name: mod_registry_lock
*
* Description:
* Get exclusive access to the module registry.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void mod_registry_lock(void);
/****************************************************************************
* Name: mod_registry_unlock
*
* Description:
* Relinquish the lock on the module registry
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void mod_registry_unlock(void);
/****************************************************************************
* Name: mod_registry_add
*
* Description:
* Add a new entry to the module registry.
*
* Input Parameters:
* modp - The module data structure to be registered.
*
* Returned Value:
* None
*
* Assumptions:
* The caller holds the lock on the module registry.
*
****************************************************************************/
void mod_registry_add(FAR struct module_s *modp);
/****************************************************************************
* Name: mod_registry_del
*
* Description:
* Remove a module entry from the registry
*
* Input Parameters:
* modp - The registry entry to be removed.
*
* Returned Value:
* Zero (OK) is returned if the registry entry was deleted. Otherwise,
* a negated errno value is returned.
*
* Assumptions:
* The caller holds the lock on the module registry.
*
****************************************************************************/
int mod_registry_del(FAR struct module_s *modp);
/****************************************************************************
* Name: mod_registry_find
*
* Description:
* Find an entry in the module registry using the name of the module.
*
* Input Parameters:
* modulename - The name of the module to be found
*
* Returned Value:
* If the registry entry is found, a pointer to the module entry is
* returned. NULL is returned if the they entry is not found.
*
* Assumptions:
* The caller holds the lock on the module registry.
*
****************************************************************************/
FAR struct module_s *mod_registry_find(FAR const char *modulename);
#endif /* __SCHED_MODULE_MODULE_H */

View File

@ -28,7 +28,7 @@
"getenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char*","FAR const char*"
"getpid","unistd.h","","pid_t"
"getsockopt","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int","int","FAR void*","FAR socklen_t*"
"insmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR struct module_s *"
"insmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR const char *","FAR const struct symtab_s *","int"
"ioctl","sys/ioctl.h","!defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long"
"kill","signal.h","!defined(CONFIG_DISABLE_SIGNALS)","int","pid_t","int"
"listen","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int"
@ -98,7 +98,7 @@
"rename","stdio.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*","FAR const char*"
"rewinddir","dirent.h","CONFIG_NFILE_DESCRIPTORS > 0","void","FAR DIR*"
"rmdir","unistd.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*"
"rmmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR struct module_s *"
"rmmod","nuttx/module.h",defined(CONFIG_MODULE),"int","FAR const char *"
"sched_getparam","sched.h","","int","pid_t","struct sched_param*"
"sched_getscheduler","sched.h","","int","pid_t"
"sched_getstreams","nuttx/sched.h","CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0","FAR struct streamlist*"

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -111,7 +111,7 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert)
*/
#ifdef CONFIG_MODULE
SYSCALL_LOOKUP(insmod, 1, STUB_insmod)
SYSCALL_LOOKUP(insmod, 3, STUB_insmod)
SYSCALL_LOOKUP(rmmod, 1, STUB_rmmod)
#endif

View File

@ -112,7 +112,8 @@ uintptr_t STUB_waitid(int nbr, uintptr_t parm1, uintptr_t parm2,
*/
#ifdef CONFIG_MODULE
uintptr_t STUB_insmod(int nbr, uintptr_t parm1);
uintptr_t STUB_insmod(int nbr, uintptr_t parm1, uintptr_t parm2,
uintptr_t parm3);
uintptr_t STUB_rmmod(int nbr, uintptr_t parm1);
#endif