[rtems commit] IMFS: Add make generic node support

Joel Sherrill joel at rtems.org
Thu Mar 29 14:14:29 UTC 2012


Module:    rtems
Branch:    master
Commit:    fe6907df2ff94131c563819515d10b176cb55a12
Changeset: http://git.rtems.org/rtems/commit/?id=fe6907df2ff94131c563819515d10b176cb55a12

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu Mar  1 11:51:34 2012 +0100

IMFS: Add make generic node support

Generic nodes are an alternative to standard drivers in RTEMS.  The
handlers of a generic node are called with less overhead compared to the
standard driver operations.  The usage of file system node handlers
enable more features like support for fsync() and fdatasync().  The
generic nodes use the reference counting of the IMFS.  This provides
automatic node destruction when the last reference vanishes.

Extend type IMFS_types_union by new type IMFS_generic_t.

Extend enum IMFS_jnode_types_t by IMFS_GENERIC.

Add functions
 o IMFS_make_generic_node(),
 o IMFS_is_imfs_instance(),
 o IMFS_generic_get_context_by_node(),
 o IMFS_generic_get_context_by_location(), and
 o IMFS_generic_get_context_by_iop().

New test fstests/fsimfsgeneric01.

---

 cpukit/libfs/Makefile.am                           |    1 +
 cpukit/libfs/src/imfs/imfs.h                       |   46 +++
 cpukit/libfs/src/imfs/imfs_make_generic_node.c     |  108 +++++
 testsuites/fstests/Makefile.am                     |    1 +
 testsuites/fstests/configure.ac                    |    1 +
 testsuites/fstests/fsimfsgeneric01/Makefile.am     |   20 +
 .../fstests/fsimfsgeneric01/fsimfsgeneric01.doc    |   11 +
 .../fstests/fsimfsgeneric01/fsimfsgeneric01.scn    |    2 +
 testsuites/fstests/fsimfsgeneric01/init.c          |  408 ++++++++++++++++++++
 9 files changed, 598 insertions(+), 0 deletions(-)

diff --git a/cpukit/libfs/Makefile.am b/cpukit/libfs/Makefile.am
index 342f5eb..c629bc9 100644
--- a/cpukit/libfs/Makefile.am
+++ b/cpukit/libfs/Makefile.am
@@ -45,6 +45,7 @@ libimfs_a_SOURCES += src/imfs/deviceerrno.c src/imfs/deviceio.c \
     src/imfs/imfs_creat.c src/imfs/imfs_debug.c src/imfs/imfs_directory.c \
     src/imfs/imfs_eval.c src/imfs/imfs_fchmod.c \
     src/imfs/imfs_fifo.c \
+    src/imfs/imfs_make_generic_node.c \
     src/imfs/imfs_fsunmount.c \
     src/imfs/imfs_handlers_device.c \
     src/imfs/imfs_handlers_directory.c src/imfs/imfs_handlers_link.c \
diff --git a/cpukit/libfs/src/imfs/imfs.h b/cpukit/libfs/src/imfs/imfs.h
index ae247c5..eca8824 100644
--- a/cpukit/libfs/src/imfs/imfs.h
+++ b/cpukit/libfs/src/imfs/imfs.h
@@ -56,6 +56,10 @@ typedef struct {
   pipe_control_t  *pipe;
 } IMFS_fifo_t;
 
+typedef struct {
+  void *context;
+} IMFS_generic_t;
+
 /*
  *  IMFS "memfile" information
  *
@@ -133,9 +137,11 @@ typedef enum {
   IMFS_MEMORY_FILE = RTEMS_FILESYSTEM_MEMORY_FILE,
   IMFS_LINEAR_FILE,
   IMFS_FIFO,
+  IMFS_GENERIC,
   IMFS_INVALID_NODE
 } IMFS_jnode_types_t;
 
+/* The IMFS_GENERIC does not count */
 #define IMFS_TYPE_COUNT (IMFS_FIFO + 1)
 
 typedef union {
@@ -146,6 +152,7 @@ typedef union {
   IMFS_memfile_t     file;
   IMFS_linearfile_t  linearfile;
   IMFS_fifo_t        fifo;
+  IMFS_generic_t     generic;
 } IMFS_types_union;
 
 typedef IMFS_jnode_t *(*IMFS_node_control_initialize)(
@@ -158,6 +165,11 @@ IMFS_jnode_t *IMFS_node_initialize_default(
   const IMFS_types_union *info
 );
 
+IMFS_jnode_t *IMFS_node_initialize_generic(
+  IMFS_jnode_t *node,
+  const IMFS_types_union *info
+);
+
 typedef IMFS_jnode_t *(*IMFS_node_control_remove)(
   IMFS_jnode_t *node,
   const IMFS_jnode_t *root_node
@@ -370,6 +382,17 @@ extern IMFS_jnode_t *IMFS_create_node_with_control(
   const IMFS_types_union *info
 );
 
+extern bool IMFS_is_imfs_instance(
+  const rtems_filesystem_location_info_t *loc
+);
+
+extern int IMFS_make_generic_node(
+  const char *path,
+  mode_t mode,
+  const IMFS_node_control *node_control,
+  void *context
+);
+
 extern int IMFS_mount(
   rtems_filesystem_mount_table_entry_t *mt_entry  /* IN */
 );
@@ -573,6 +596,29 @@ static inline IMFS_jnode_t *IMFS_create_node(
   );
 }
 
+static inline void *IMFS_generic_get_context_by_node(
+  const IMFS_jnode_t *node
+)
+{
+  return node->info.generic.context;
+}
+
+static inline void *IMFS_generic_get_context_by_location(
+  const rtems_filesystem_location_info_t *loc
+)
+{
+  const IMFS_jnode_t *node = (const IMFS_jnode_t *) loc->node_access;
+
+  return IMFS_generic_get_context_by_node( node );
+}
+
+static inline void *IMFS_generic_get_context_by_iop(
+  const rtems_libio_t *iop
+)
+{
+  return IMFS_generic_get_context_by_location( &iop->pathinfo );
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpukit/libfs/src/imfs/imfs_make_generic_node.c b/cpukit/libfs/src/imfs/imfs_make_generic_node.c
new file mode 100644
index 0000000..5b7a7d9
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_make_generic_node.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Obere Lagerstr. 30
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include "imfs.h"
+
+IMFS_jnode_t *IMFS_node_initialize_generic(
+  IMFS_jnode_t *node,
+  const IMFS_types_union *info
+)
+{
+  node->info.generic.context = info->generic.context;
+
+  return node;
+}
+
+bool IMFS_is_imfs_instance(
+  const rtems_filesystem_location_info_t *loc
+)
+{
+  const char *type = loc->mt_entry->type;
+
+  return strcmp(type, RTEMS_FILESYSTEM_TYPE_IMFS) == 0
+    || strcmp(type, RTEMS_FILESYSTEM_TYPE_MINIIMFS) == 0;
+}
+
+int IMFS_make_generic_node(
+  const char *path,
+  mode_t mode,
+  const IMFS_node_control *node_control,
+  void *context
+)
+{
+  int rv = 0;
+
+  mode &= ~rtems_filesystem_umask;
+
+  switch (mode & S_IFMT) {
+    case S_IFBLK:
+    case S_IFCHR:
+    case S_IFIFO:
+    case S_IFREG:
+      break;
+    default:
+      errno = EINVAL;
+      rv = -1;
+      break;
+  }
+  
+  if ( rv == 0 ) {
+    if ( node_control->imfs_type == IMFS_GENERIC ) {
+      rtems_filesystem_eval_path_context_t ctx;
+      int eval_flags = RTEMS_FS_FOLLOW_LINK
+        | RTEMS_FS_MAKE
+        | RTEMS_FS_EXCLUSIVE;
+      const rtems_filesystem_location_info_t *currentloc =
+        rtems_filesystem_eval_path_start( &ctx, path, eval_flags );
+
+      if ( IMFS_is_imfs_instance( currentloc ) ) {
+        IMFS_types_union info;
+        IMFS_jnode_t *new_node;
+
+        info.generic.context = context;
+        new_node = IMFS_create_node_with_control(
+          currentloc,
+          node_control,
+          rtems_filesystem_eval_path_get_token( &ctx ),
+          rtems_filesystem_eval_path_get_tokenlen( &ctx ),
+          mode,
+          &info
+        );
+
+        if ( new_node != NULL ) {
+          IMFS_jnode_t *parent = currentloc->node_access;
+
+          IMFS_update_ctime( parent );
+          IMFS_update_mtime( parent );
+        } else {
+          rv = -1;
+        }
+      } else {
+        rtems_filesystem_eval_path_error( &ctx, ENOTSUP );
+        rv = -1;
+      }
+
+      rtems_filesystem_eval_path_cleanup( &ctx );
+    } else {
+      errno = EINVAL;
+      rv = -1;
+    }
+  }
+
+  return rv;
+}
diff --git a/testsuites/fstests/Makefile.am b/testsuites/fstests/Makefile.am
index 535862b..d731eb6 100644
--- a/testsuites/fstests/Makefile.am
+++ b/testsuites/fstests/Makefile.am
@@ -31,6 +31,7 @@ SUBDIRS += mrfs_fsrdwr
 SUBDIRS += mrfs_fssymlink
 SUBDIRS += mrfs_fstime
 SUBDIRS += fsnofs01
+SUBDIRS += fsimfsgeneric01
 
 EXTRA_DIST =
 EXTRA_DIST += support/ramdisk_support.c
diff --git a/testsuites/fstests/configure.ac b/testsuites/fstests/configure.ac
index ce3bdf7..f2ca983 100644
--- a/testsuites/fstests/configure.ac
+++ b/testsuites/fstests/configure.ac
@@ -105,6 +105,7 @@ mrfs_fsrdwr/Makefile
 mrfs_fssymlink/Makefile
 mrfs_fstime/Makefile
 fsnofs01/Makefile
+fsimfsgeneric01/Makefile
 
 ])
 AC_OUTPUT
diff --git a/testsuites/fstests/fsimfsgeneric01/Makefile.am b/testsuites/fstests/fsimfsgeneric01/Makefile.am
new file mode 100644
index 0000000..e8ab9f4
--- /dev/null
+++ b/testsuites/fstests/fsimfsgeneric01/Makefile.am
@@ -0,0 +1,20 @@
+rtems_tests_PROGRAMS = fsimfsgeneric01
+fsimfsgeneric01_SOURCES = init.c
+
+dist_rtems_tests_DATA = fsimfsgeneric01.scn fsimfsgeneric01.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(fsimfsgeneric01_OBJECTS)
+LINK_LIBS = $(fsimfsgeneric01_LDLIBS)
+
+fsimfsgeneric01$(EXEEXT): $(fsimfsgeneric01_OBJECTS) $(fsimfsgeneric01_DEPENDENCIES)
+	@rm -f fsimfsgeneric01$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/fstests/fsimfsgeneric01/fsimfsgeneric01.doc b/testsuites/fstests/fsimfsgeneric01/fsimfsgeneric01.doc
new file mode 100644
index 0000000..120fccb
--- /dev/null
+++ b/testsuites/fstests/fsimfsgeneric01/fsimfsgeneric01.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: fsimfsgeneric01
+
+directives:
+
+  IMFS_IMFS_make_generic_node
+
+concepts:
+
+  TBD
diff --git a/testsuites/fstests/fsimfsgeneric01/fsimfsgeneric01.scn b/testsuites/fstests/fsimfsgeneric01/fsimfsgeneric01.scn
new file mode 100644
index 0000000..fa34add
--- /dev/null
+++ b/testsuites/fstests/fsimfsgeneric01/fsimfsgeneric01.scn
@@ -0,0 +1,2 @@
+*** TEST FSIMFSGENERIC 1 ***
+*** END OF TEST FSIMFSGENERIC 1 ***
diff --git a/testsuites/fstests/fsimfsgeneric01/init.c b/testsuites/fstests/fsimfsgeneric01/init.c
new file mode 100644
index 0000000..d7abad3
--- /dev/null
+++ b/testsuites/fstests/fsimfsgeneric01/init.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Obere Lagerstr. 30
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include "tmacros.h"
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <rtems/imfs.h>
+#include <rtems/malloc.h>
+
+typedef enum {
+  TEST_NEW,
+  TEST_INITIALIZED,
+  TEST_FSTAT_OPEN,
+  TEST_OPEN,
+  TEST_READ,
+  TEST_WRITE,
+  TEST_IOCTL,
+  TEST_LSEEK,
+  TEST_FTRUNCATE,
+  TEST_FSYNC,
+  TEST_FDATASYNC,
+  TEST_FCNTL,
+  TEST_CLOSED,
+  TEST_FSTAT_UNLINK,
+  TEST_REMOVED,
+  TEST_DESTROYED
+} test_state;
+
+static test_state global_state = TEST_NEW;
+
+static int handler_open(
+  rtems_libio_t *iop,
+  const char *path,
+  int oflag,
+  mode_t mode
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_FSTAT_OPEN);
+  *state = TEST_OPEN;
+
+  return 0;
+}
+
+static int handler_close(
+  rtems_libio_t *iop
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_FCNTL);
+  *state = TEST_CLOSED;
+
+  return 0;
+}
+
+static ssize_t handler_read(
+  rtems_libio_t *iop,
+  void *buffer,
+  size_t count
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_OPEN);
+  *state = TEST_READ;
+
+  return 0;
+}
+
+static ssize_t handler_write(
+  rtems_libio_t *iop,
+  const void *buffer,
+  size_t count
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_READ);
+  *state = TEST_WRITE;
+
+  return 0;
+}
+
+static int handler_ioctl(
+  rtems_libio_t *iop,
+  uint32_t request,
+  void *buffer
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_WRITE);
+  *state = TEST_IOCTL;
+
+  return 0;
+}
+
+static off_t handler_lseek(
+  rtems_libio_t *iop,
+  off_t length,
+  int whence
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_IOCTL);
+  *state = TEST_LSEEK;
+
+  return 0;
+}
+
+static int handler_fstat(
+  const rtems_filesystem_location_info_t *loc,
+  struct stat *buf
+)
+{
+  test_state *state = IMFS_generic_get_context_by_location(loc);
+
+  switch (*state) {
+    case TEST_INITIALIZED:
+      *state = TEST_FSTAT_OPEN;
+      break;
+    case TEST_CLOSED:
+      *state = TEST_FSTAT_UNLINK;
+      break;
+    default:
+      rtems_test_assert(0);
+      break;
+  }
+
+  return rtems_filesystem_default_fstat(loc, buf);
+}
+
+static int handler_ftruncate(
+  rtems_libio_t *iop,
+  off_t length
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_LSEEK);
+  *state = TEST_FTRUNCATE;
+
+  return 0;
+}
+
+static int handler_fsync(
+  rtems_libio_t *iop
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_FTRUNCATE);
+  *state = TEST_FSYNC;
+
+  return 0;
+}
+
+static int handler_fdatasync(
+  rtems_libio_t *iop
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_FSYNC);
+  *state = TEST_FDATASYNC;
+
+  return 0;
+}
+
+static int handler_fcntl(
+  rtems_libio_t *iop,
+  int cmd
+)
+{
+  test_state *state = IMFS_generic_get_context_by_iop(iop);
+
+  rtems_test_assert(*state == TEST_FDATASYNC);
+  *state = TEST_FCNTL;
+
+  return 0;
+}
+
+static const rtems_filesystem_file_handlers_r node_handlers = {
+  .open_h = handler_open,
+  .close_h = handler_close,
+  .read_h = handler_read,
+  .write_h = handler_write,
+  .ioctl_h = handler_ioctl,
+  .lseek_h = handler_lseek,
+  .fstat_h = handler_fstat,
+  .ftruncate_h = handler_ftruncate,
+  .fsync_h = handler_fsync,
+  .fdatasync_h = handler_fdatasync,
+  .fcntl_h = handler_fcntl
+};
+
+static IMFS_jnode_t *node_initialize(
+  IMFS_jnode_t *node,
+  const IMFS_types_union *info
+)
+{
+  test_state *state = NULL;
+
+  node = IMFS_node_initialize_generic(node, info);
+  state = IMFS_generic_get_context_by_node(node);
+
+  rtems_test_assert(*state == TEST_NEW);
+  *state = TEST_INITIALIZED;
+
+  return node;
+}
+
+static IMFS_jnode_t *node_remove(
+  IMFS_jnode_t *node,
+  const IMFS_jnode_t *root_node
+)
+{
+  test_state *state = IMFS_generic_get_context_by_node(node);
+
+  rtems_test_assert(*state == TEST_FSTAT_UNLINK);
+  *state = TEST_REMOVED;
+
+  return node;
+}
+
+static IMFS_jnode_t *node_destroy(IMFS_jnode_t *node)
+{
+  test_state *state = IMFS_generic_get_context_by_node(node);
+
+  rtems_test_assert(*state == TEST_REMOVED);
+  *state = TEST_DESTROYED;
+
+  return node;
+}
+
+static const IMFS_node_control node_control = {
+  .imfs_type = IMFS_GENERIC,
+  .handlers = &node_handlers,
+  .node_initialize = node_initialize,
+  .node_remove = node_remove,
+  .node_destroy = node_destroy
+};
+
+static void test_imfs_make_generic_node(void)
+{
+  int rv = 0;
+  int fd = 0;
+  const char *path = "generic";
+  char buf [1];
+  ssize_t n = 0;
+  off_t off = 0;
+
+  rv = IMFS_make_generic_node(
+    path,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
+    &node_control,
+    &global_state
+  );
+  rtems_test_assert(rv == 0);
+
+  fd = open(path, O_RDWR);
+  rtems_test_assert(fd >= 0);
+
+  n = read(fd, buf, sizeof(buf));
+  rtems_test_assert(n == 0);
+
+  n = write(fd, buf, sizeof(buf));
+  rtems_test_assert(n == 0);
+
+  rv = ioctl(fd, 0);
+  rtems_test_assert(rv == 0);
+
+  off = lseek(fd, off, SEEK_SET);
+  rtems_test_assert(off == 0);
+
+  rv = ftruncate(fd, 0);
+  rtems_test_assert(rv == 0);
+
+  rv = fsync(fd);
+  rtems_test_assert(rv == 0);
+
+  rv = fdatasync(fd);
+  rtems_test_assert(rv == 0);
+
+  rv = fcntl(fd, F_GETFD);
+  rtems_test_assert(rv >= 0);
+
+  rv = close(fd);
+  rtems_test_assert(rv == 0);
+
+  rv = unlink(path);
+  rtems_test_assert(rv == 0);
+
+  rtems_test_assert(global_state == TEST_DESTROYED);
+}
+
+static const IMFS_node_control node_invalid_control = {
+  .imfs_type = IMFS_DIRECTORY,
+  .handlers = &node_handlers,
+  .node_initialize = node_initialize,
+  .node_remove = node_remove,
+  .node_destroy = node_destroy
+};
+
+static void test_imfs_make_generic_node_errors(void)
+{
+  int rv = 0;
+  const char *path = "generic";
+  rtems_chain_control *chain = &rtems_filesystem_mount_table;
+  rtems_filesystem_mount_table_entry_t *mt_entry =
+    (rtems_filesystem_mount_table_entry_t *) rtems_chain_first(chain);
+  const char *type = mt_entry->type;
+  void *opaque = NULL;
+
+  errno = 0;
+  rv = IMFS_make_generic_node(
+    path,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
+    &node_invalid_control,
+    NULL
+  );
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == EINVAL);
+
+  errno = 0;
+  rv = IMFS_make_generic_node(
+    path,
+    S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO,
+    &node_control,
+    NULL
+  );
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == EINVAL);
+
+  mt_entry->type = "XXX";
+  errno = 0;
+  rv = IMFS_make_generic_node(
+    path,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
+    &node_control,
+    NULL
+  );
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == ENOTSUP);
+  mt_entry->type = type;
+
+  opaque = rtems_heap_greedy_allocate(0);
+  errno = 0;
+  rv = IMFS_make_generic_node(
+    path,
+    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
+    &node_control,
+    NULL
+  );
+  rtems_test_assert(rv == -1);
+  rtems_test_assert(errno == ENOMEM);
+  rtems_heap_greedy_free(opaque);
+}
+
+static void Init(rtems_task_argument arg)
+{
+  printf("\n\n*** TEST FSIMFSGENERIC 1 ***\n");
+
+  test_imfs_make_generic_node();
+  test_imfs_make_generic_node_errors();
+
+  printf("*** END OF TEST FSIMFSGENERIC 1 ***\n");
+
+  rtems_test_exit(0);
+}
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4
+
+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>




More information about the vc mailing list