[rtems commit] PR2040: libtests/flashdisk01: New test

Sebastian Huber sebh at rtems.org
Wed Mar 14 05:17:04 CDT 2012


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

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Fri Mar  9 14:46:40 2012 +0100

PR2040: libtests/flashdisk01: New test

---

 testsuites/libtests/Makefile.am                    |    1 +
 testsuites/libtests/configure.ac                   |    1 +
 testsuites/libtests/flashdisk01/Makefile.am        |   19 +
 testsuites/libtests/flashdisk01/flashdisk01.doc    |   11 +
 testsuites/libtests/flashdisk01/flashdisk01.scn    |  265 +++++++
 testsuites/libtests/flashdisk01/init.c             |  353 +++++++++
 testsuites/libtests/flashdisk01/test-file-system.c |  832 ++++++++++++++++++++
 testsuites/libtests/flashdisk01/test-file-system.h |   52 ++
 8 files changed, 1534 insertions(+), 0 deletions(-)

diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
index 0e30a51..3bcd8c2 100644
--- a/testsuites/libtests/Makefile.am
+++ b/testsuites/libtests/Makefile.am
@@ -5,6 +5,7 @@
 ACLOCAL_AMFLAGS = -I ../aclocal
 
 SUBDIRS = POSIX
+SUBDIRS += flashdisk01
 
 SUBDIRS += bspcmdline01 cpuuse devfs01 devfs02 devfs03 devfs04 \
     deviceio01 devnullfatal01 dumpbuf01 gxx01 \
diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac
index b634ff8..ec022bc 100644
--- a/testsuites/libtests/configure.ac
+++ b/testsuites/libtests/configure.ac
@@ -43,6 +43,7 @@ AM_CONDITIONAL(NETTESTS,test "$rtems_cv_RTEMS_NETWORKING" = "yes")
 
 # Explicitly list all Makefiles here
 AC_CONFIG_FILES([Makefile
+flashdisk01/Makefile
 block01/Makefile
 block02/Makefile
 block03/Makefile
diff --git a/testsuites/libtests/flashdisk01/Makefile.am b/testsuites/libtests/flashdisk01/Makefile.am
new file mode 100644
index 0000000..fd34fe6
--- /dev/null
+++ b/testsuites/libtests/flashdisk01/Makefile.am
@@ -0,0 +1,19 @@
+rtems_tests_PROGRAMS = flashdisk01
+flashdisk01_SOURCES = init.c test-file-system.c
+
+dist_rtems_tests_DATA = flashdisk01.scn flashdisk01.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 = $(flashdisk01_OBJECTS)
+LINK_LIBS = $(flashdisk01_LDLIBS)
+
+flashdisk01$(EXEEXT): $(flashdisk01_OBJECTS) $(flashdisk01_DEPENDENCIES)
+	@rm -f flashdisk01$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/libtests/flashdisk01/flashdisk01.doc b/testsuites/libtests/flashdisk01/flashdisk01.doc
new file mode 100644
index 0000000..6bb1205
--- /dev/null
+++ b/testsuites/libtests/flashdisk01/flashdisk01.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: flashdisk01
+
+directives:
+
+  TBD
+
+concepts:
+
+  TBD
diff --git a/testsuites/libtests/flashdisk01/flashdisk01.scn b/testsuites/libtests/flashdisk01/flashdisk01.scn
new file mode 100644
index 0000000..5dcc4b6
--- /dev/null
+++ b/testsuites/libtests/flashdisk01/flashdisk01.scn
@@ -0,0 +1,265 @@
+*** TEST FLASHDISK 1 ***
+[00]: start
+[00]: mount: /dev/fdda -> /mnt
+[00]: init root: /mnt
+[00]: create dir: 1804928587
+[00]: create dir: 959030623
+[00]: create dir: 1903590565
+[00]: open file: file
+[00]: sleep: 700 ms
+[00]: close file
+[00]: sleep: 200 ms
+[00]: open dir: 959030623
+[00]: create dir: 838545539
+[00]: create file: 1594243340
+[00]: create file: 162216788
+[00]: create file: 1841205112
+[00]: sleep: 700 ms
+[00]: remove dir: 838545539
+[00]: create dir: 1143741253
+[00]: remove file: 1594243340
+[00]: sleep: 400 ms
+[00]: close dir
+[00]: sleep: 400 ms
+[00]: create file: 832100416
+[00]: open dir: 1903590565
+[00]: create file: 1401208270
+[00]: create dir: 2032315143
+[00]: create dir: 2026989069
+[00]: close dir
+[00]: open dir: 1804928587
+[00]: close dir
+[00]: open dir: 1804928587
+[00]: sleep: 100 ms
+[00]: create dir: 650320721
+[00]: sleep: 500 ms
+[00]: create dir: 1857409239
+[00]: create file: 2060801678
+[00]: create dir: 490998763
+[00]: create dir: 644928527
+[00]: create file: 1758287264
+[00]: close dir
+[00]: sleep: 500 ms
+[00]: open file: file
+[00]: read from file
+[00]: read from file
+[00]: read from file
+[00]: sleep: 700 ms
+[00]: read from file
+[00]: sleep: 200 ms
+[00]: sleep: 300 ms
+[00]: read from file
+[00]: append to file
+[00]: read from file
+[00]: close file
+[00]: remove dir: 1804928587
+[00]: create file: 2073894790
+[00]: sleep: 900 ms
+[00]: create dir: 472737403
+[00]: remove dir: 1903590565
+[00]: create dir: 689486081
+[00]: create dir: 373636079
+[00]: remove file: file
+[00]: create dir: 1506727461
+[00]: open dir: 959030623
+[00]: create dir: 1029668001
+[00]: remove file: 162216788
+[00]: close dir
+[00]: sleep: 400 ms
+[00]: open dir: 959030623
+[00]: remove file: 1841205112
+[00]: create file: 378843792
+[00]: sleep: 1000 ms
+[00]: create file: 1871951748
+[00]: open dir: 1143741253
+[00]: create file: 855915646
+[00]: sleep: 700 ms
+[00]: create file: 2008730550
+[00]: close dir
+[00]: create file: 1327563176
+[00]: remove dir: 1143741253
+[00]: create file: 1384249492
+[00]: close dir
+[00]: remove dir: 959030623
+[00]: open file: 832100416
+[00]: read from file
+[00]: sleep: 400 ms
+[00]: close file
+[00]: open file: 832100416
+[00]: close file
+[00]: create dir: 2025552021
+[00]: remove dir: 959030623
+[00]: create dir: 1178339711
+[00]: remove file: 832100416
+[00]: remove file: 2073894790
+[00]: open dir: 1506727461
+[00]: sleep: 700 ms
+[00]: close dir
+[00]: sleep: 300 ms
+[00]: open dir: 1506727461
+[00]: create dir: 1625748679
+[00]: close dir
+[00]: remove dir: 689486081
+[00]: remove dir: 959030623
+[00]: open dir: 959030623
+[00]: sleep: 1000 ms
+[00]: close dir
+[00]: sleep: 100 ms
+[00]: open dir: 959030623
+[00]: create dir: 1128727833
+[00]: create file: 1203746106
+[00]: open dir: 1128727833
+[00]: create dir: 58221889
+[00]: create file: 611814452
+[00]: create dir: 420219909
+[00]: close dir
+[00]: remove file: 1384249492
+[00]: close dir
+[00]: open dir: 959030623
+[00]: close dir
+[00]: sleep: 800 ms
+[00]: remove dir: 1506727461
+[00]: create file: 550820384
+[00]: create file: 833699694
+[00]: remove dir: 1506727461
+[00]: create dir: 861614531
+[00]: remove dir: 1506727461
+[00]: create dir: 846638047
+[00]: remove dir: 1506727461
+[00]: create dir: 1766470371
+[00]: remove dir: 959030623
+[00]: create file: 1969337196
+[00]: remove dir: 1506727461
+[00]: create file: 1937189238
+[00]: remove dir: 959030623
+[00]: create dir: 1615521955
+[00]: remove dir: 959030623
+[00]: sleep: 500 ms
+[00]: open dir: 1506727461
+[00]: create file: 926653184
+[00]: remove dir: 1625748679
+[00]: close dir
+[00]: create dir: 975747319
+[00]: open dir: 959030623
+[00]: open file: 1871951748
+[00]: sleep: 600 ms
+[00]: close file
+[00]: sleep: 800 ms
+[00]: remove file: 378843792
+[00]: open file: 1203746106
+[00]: read from file
+[00]: append to file
+[00]: sleep: 600 ms
+[00]: close file
+[00]: open file: 1871951748
+[00]: append to file
+[00]: close file
+[00]: remove file: 1871951748
+[00]: sleep: 400 ms
+[00]: create file: 1835979858
+[00]: open dir: 1128727833
+[00]: create dir: 862728993
+[00]: sleep: 700 ms
+[00]: remove dir: 862728993
+[00]: close dir
+[00]: close dir
+[00]: open dir: 975747319
+[00]: sleep: 400 ms
+[00]: create dir: 1840098529
+[00]: create file: 231405798
+[00]: remove dir: 1840098529
+[00]: close dir
+[00]: remove file: 550820384
+[00]: create file: 1020303340
+[00]: create dir: 895068705
+[00]: open dir: 975747319
+[00]: close dir
+[00]: open file: 1020303340
+[00]: read from file
+[00]: close file
+[00]: create dir: 1993404773
+[00]: remove file: 1020303340
+[00]: create dir: 2112395285
+[00]: create dir: 81202983
+[00]: remove dir: 975747319
+[00]: remove dir: 959030623
+[00]: create dir: 467069459
+[00]: open dir: 1506727461
+[00]: create file: 612609068
+[00]: create dir: 1793174441
+[00]: create file: 710808000
+[00]: sleep: 300 ms
+[00]: create file: 897370450
+[00]: create file: 1901152134
+[00]: sleep: 200 ms
+[00]: close dir
+[00]: open dir: 1506727461
+[00]: close dir
+[00]: sleep: 800 ms
+[00]: create file: 906254788
+[00]: remove dir: 467069459
+[00]: remove dir: 1506727461
+[00]: open dir: 895068705
+[00]: close dir
+[00]: create file: 1216543556
+[00]: create file: 37176518
+[00]: open dir: 2112395285
+[00]: close dir
+[00]: create dir: 659416143
+[00]: remove file: 37176518
+[00]: sleep: 500 ms
+[00]: remove dir: 895068705
+[00]: create dir: 1507289677
+[00]: open dir: 959030623
+[00]: create file: 1766335976
+[00]: close dir
+[00]: sleep: 400 ms
+[00]: open dir: 2112395285
+[00]: create dir: 1476817327
+[00]: close dir
+[00]: create dir: 1841667551
+[00]: remove dir: 2112395285
+[00]: open dir: 1507289677
+[00]: close dir
+[00]: create file: 1610238546
+[00]: create file: 220151308
+[00]: remove dir: 1507289677
+[00]: open file: 1216543556
+[00]: append to file
+[00]: append to file
+[00]: close file
+[00]: remove file: 1216543556
+[00]: open dir: 959030623
+[00]: sleep: 500 ms
+[00]: create file: 1508553554
+[00]: create file: 1742399670
+[00]: sleep: 100 ms
+[00]: close dir
+[00]: create dir: 2113094209
+[00]: remove dir: 959030623
+[00]: remove file: 1610238546
+[00]: create dir: 2146380029
+[00]: sleep: 700 ms
+[00]: create file: 1557834172
+[00]: remove dir: 2146380029
+[00]: finish
+fdisk:Flash Disk Driver Status : 2.0
+fdisk:Block count       124
+fdisk:Unavail blocks    32
+fdisk:Starvations       76
+fdisk:Available queue   2 (2)
+fdisk:Used queue        2 (2)
+fdisk:Erase queue       0 (0)
+fdisk:Failed queue      0 (0)
+fdisk:Queue total       4 of 4, ok
+fdisk:Device count      1
+fdisk: Device           0
+fdisk:  Segment count   4
+fdisk:    0 A--- p: 31 a: 30/ 30 u:  0/  0 e:  1/  1 br:30
+fdisk:    1 A--- p: 31 a:  0/  0 u:  0/  0 e: 31/ 31 br:0
+fdisk:    2 -U-- p: 31 a: 31/ 31 u:  0/  0 e:  0/  0 br:31
+fdisk:    3 -U-- p: 31 a: 31/ 31 u:  0/  0 e:  0/  0 br:31
+fdisk:Used List:
+fdisk:    0 00:002 u:  0
+fdisk:    1 00:003 u:  0
+*** END OF TEST FLASHDISK 1 ***
diff --git a/testsuites/libtests/flashdisk01/init.c b/testsuites/libtests/flashdisk01/init.c
new file mode 100644
index 0000000..d9f26f3
--- /dev/null
+++ b/testsuites/libtests/flashdisk01/init.c
@@ -0,0 +1,353 @@
+/*
+ * 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 <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <rtems/flashdisk.h>
+#include <rtems/libio.h>
+#include <rtems/blkdev.h>
+#include <rtems/rtems-rfs-format.h>
+
+#include "test-file-system.h"
+
+#define FLASHDISK_CONFIG_COUNT 1
+
+#define FLASHDISK_DEVICE_COUNT 1
+
+#define FLASHDISK_SEGMENT_COUNT 4
+
+#define FLASHDISK_SEGMENT_SIZE (16 * 1024)
+
+#define FLASHDISK_BLOCK_SIZE 512
+
+#define FLASHDISK_BLOCKS_PER_SEGMENT \
+  (FLASHDISK_SEGMENT_SIZE / FLASHDISK_BLOCK_SIZE)
+
+#define FLASHDISK_SIZE \
+  (FLASHDISK_SEGMENT_COUNT * FLASHDISK_SEGMENT_SIZE)
+
+static const rtems_rfs_format_config rfs_config;
+
+static const char device [] = "/dev/fdda";
+
+static const char mnt [] = "/mnt";
+
+static const char file [] = "/mnt/file";
+
+static uint8_t flashdisk_data [FLASHDISK_SIZE];
+
+static void flashdisk_print_status(const char *disk_path)
+{
+  int rv;
+  int fd = open(disk_path, O_RDWR);
+  rtems_test_assert(fd >= 0);
+
+  rv = ioctl(fd, RTEMS_FDISK_IOCTL_PRINT_STATUS);
+  rtems_test_assert(rv == 0);
+
+  rv = close(fd);
+  rtems_test_assert(rv == 0);
+}
+
+static int test_rfs_mount_handler(
+  const char *disk_path,
+  const char *mount_path,
+  void *arg
+)
+{
+  return mount_and_make_target_path(
+    disk_path,
+    mount_path,
+    RTEMS_FILESYSTEM_TYPE_RFS,
+    RTEMS_FILESYSTEM_READ_WRITE,
+    NULL
+  );
+}
+
+static int test_rfs_format_handler(
+  const char *disk_path,
+  void *arg
+)
+{
+  flashdisk_print_status(disk_path);
+
+  rtems_test_assert(0);
+
+  errno = EIO;
+
+  return -1;
+}
+
+static const test_file_system_handler test_rfs_handler = {
+  .mount = test_rfs_mount_handler,
+  .format = test_rfs_format_handler
+};
+
+static void test(void)
+{
+  int rv;
+  const void *data = NULL;
+
+  rv = mkdir(mnt, S_IRWXU | S_IRWXG | S_IRWXO);
+  rtems_test_assert(rv == 0);
+
+  rv = rtems_rfs_format(device, &rfs_config);
+  rtems_test_assert(rv == 0);
+
+  rv = mount(
+    device,
+    mnt,
+    RTEMS_FILESYSTEM_TYPE_RFS,
+    RTEMS_FILESYSTEM_READ_WRITE,
+    data
+  );
+  rtems_test_assert(rv == 0);
+
+  rv = mknod(file, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO, 0);
+  rtems_test_assert(rv == 0);
+
+  rv = unmount(mnt);
+  rtems_test_assert(rv == 0);
+
+  test_file_system_with_handler(
+    0,
+    device,
+    mnt,
+    &test_rfs_handler,
+    NULL
+  );
+
+  flashdisk_print_status(device);
+}
+
+static void Init(rtems_task_argument arg)
+{
+  puts("\n\n*** TEST FLASHDISK 1 ***");
+
+  test();
+
+  puts("*** END OF TEST FLASHDISK 1 ***");
+
+  rtems_test_exit(0);
+}
+
+static void erase_device(void)
+{
+  memset(&flashdisk_data [0], 0xff, FLASHDISK_SIZE);
+}
+
+static rtems_device_driver flashdisk_initialize(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void *arg
+)
+{
+  erase_device();
+
+  return rtems_fdisk_initialize(major, minor, arg);
+}
+
+static uint8_t *get_data_pointer(
+  const rtems_fdisk_segment_desc *sd,
+  uint32_t segment,
+  uint32_t offset
+)
+{
+  offset += sd->offset + (segment - sd->segment) * sd->size;
+
+  return &flashdisk_data [offset];
+}
+
+static int flashdisk_read(
+  const rtems_fdisk_segment_desc *sd,
+  uint32_t device,
+  uint32_t segment,
+  uint32_t offset,
+  void *buffer,
+  uint32_t size
+)
+{
+  int eno = 0;
+  const uint8_t *data = get_data_pointer(sd, segment, offset);
+
+  memcpy(buffer, data, size);
+
+  return eno;
+}
+
+static int flashdisk_write(
+  const rtems_fdisk_segment_desc *sd,
+  uint32_t device,
+  uint32_t segment,
+  uint32_t offset,
+  const void *buffer,
+  uint32_t size
+)
+{
+  int eno = 0;
+  uint8_t *data = get_data_pointer(sd, segment, offset);
+
+  memcpy(data, buffer, size);
+
+  return eno;
+}
+
+static int flashdisk_blank(
+  const rtems_fdisk_segment_desc *sd,
+  uint32_t device,
+  uint32_t segment,
+  uint32_t offset,
+  uint32_t size
+)
+{
+  int eno = 0;
+  const uint8_t *current = get_data_pointer(sd, segment, offset);
+  const uint8_t *end = current + size;;
+
+  while (eno == 0 && current != end) {
+    if (*current != 0xff) {
+      eno = EIO;
+    }
+    ++current;
+  }
+
+  return eno;
+}
+
+static int flashdisk_verify(
+  const rtems_fdisk_segment_desc *sd,
+  uint32_t device,
+  uint32_t segment,
+  uint32_t offset,
+  const void *buffer,
+  uint32_t size
+)
+{
+  int eno = 0;
+  uint8_t *data = get_data_pointer(sd, segment, offset);
+
+  if (memcmp(data, buffer, size) != 0) {
+    eno = EIO;
+  }
+
+  return eno;
+}
+
+static int flashdisk_erase(
+  const rtems_fdisk_segment_desc *sd,
+  uint32_t device,
+  uint32_t segment
+)
+{
+  int eno = 0;
+  uint8_t *data = get_data_pointer(sd, segment, 0);
+
+  memset(data, 0xff, sd->size);
+
+  return eno;
+}
+
+static int flashdisk_erase_device(
+  const rtems_fdisk_device_desc *sd,
+  uint32_t device
+)
+{
+  int eno = 0;
+
+  erase_device();
+
+  return eno;
+}
+
+static const rtems_fdisk_segment_desc flashdisk_segment_desc = {
+  .count = FLASHDISK_SEGMENT_COUNT,
+  .segment = 0,
+  .offset = 0,
+  .size = FLASHDISK_SEGMENT_SIZE
+};
+
+static const rtems_fdisk_driver_handlers flashdisk_ops = {
+  .read = flashdisk_read,
+  .write = flashdisk_write,
+  .blank = flashdisk_blank,
+  .verify = flashdisk_verify,
+  .erase = flashdisk_erase,
+  .erase_device = flashdisk_erase_device
+};
+
+static const rtems_fdisk_device_desc flashdisk_device = {
+  .segment_count = 1,
+  .segments = &flashdisk_segment_desc,
+  .flash_ops = &flashdisk_ops
+};
+
+const rtems_flashdisk_config
+rtems_flashdisk_configuration [FLASHDISK_CONFIG_COUNT] = {
+  {
+    .block_size = FLASHDISK_BLOCK_SIZE,
+    .device_count = FLASHDISK_DEVICE_COUNT,
+    .devices = &flashdisk_device,
+    .flags = RTEMS_FDISK_CHECK_PAGES
+      | RTEMS_FDISK_BLANK_CHECK_BEFORE_WRITE,
+    .unavail_blocks = FLASHDISK_BLOCKS_PER_SEGMENT,
+    .compact_segs = 2,
+    .avail_compact_segs = 1,
+    .info_level = 0
+  }
+};
+
+uint32_t rtems_flashdisk_configuration_size = FLASHDISK_CONFIG_COUNT;
+
+#define FLASHDISK_DRIVER { \
+  .initialization_entry = flashdisk_initialize, \
+  .open_entry = rtems_blkdev_generic_open, \
+  .close_entry = rtems_blkdev_generic_close, \
+  .read_entry = rtems_blkdev_generic_read, \
+  .write_entry = rtems_blkdev_generic_write, \
+  .control_entry = rtems_blkdev_generic_ioctl \
+}
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_EXTRA_DRIVERS FLASHDISK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
+
+#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 6
+
+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
+#define CONFIGURE_FILESYSTEM_RFS
+
+#define CONFIGURE_MAXIMUM_TASKS 2
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+
+#define CONFIGURE_MINIMUM_TASK_STACK_SIZE (32 * 1024)
+
+#define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/libtests/flashdisk01/test-file-system.c b/testsuites/libtests/flashdisk01/test-file-system.c
new file mode 100644
index 0000000..d3515d0
--- /dev/null
+++ b/testsuites/libtests/flashdisk01/test-file-system.c
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 2010-2012 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Obere Lagerstr. 30
+ *  82178 Puchheim
+ *  Germany
+ *  <info 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.
+ */
+
+#include "test-file-system.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/endian.h>
+
+#define ASSERT_SC(sc) assert((sc) == RTEMS_SUCCESSFUL)
+
+#define BUFFER_SIZE (32 * 1024)
+
+#define HEADER_SIZE 8
+
+/**
+ * @brief Test states.
+ *
+ * digraph {
+ *   INIT -> MOUNT;
+ *   MOUNT -> INIT_ROOT;
+ *   MOUNT -> FORMAT;
+ *   INIT_ROOT -> CHOOSE_DIR_ACTION
+ *   INIT_ROOT -> ERROR;
+ *   CHOOSE_DIR_ACTION -> DIR_OPEN;
+ *   CHOOSE_DIR_ACTION -> DIR_CLOSE;
+ *   CHOOSE_DIR_ACTION -> DIR_CREATE;
+ *   CHOOSE_DIR_ACTION -> DIR_DELETE;
+ *   CHOOSE_DIR_ACTION -> DIR_SLEEP;
+ *   DIR_OPEN -> CHOOSE_DIR_ACTION;
+ *   DIR_OPEN -> CHOOSE_FILE_ACTION;
+ *   DIR_OPEN -> ERROR;
+ *   DIR_CLOSE -> CHOOSE_DIR_ACTION;
+ *   DIR_CLOSE -> ERROR;
+ *   DIR_CREATE -> CHOOSE_DIR_ACTION;
+ *   DIR_CREATE -> DIR_DELETE;
+ *   DIR_CREATE -> ERROR;
+ *   DIR_DELETE -> CHOOSE_DIR_ACTION;
+ *   DIR_DELETE -> ERROR;
+ *   DIR_SLEEP -> CHOOSE_DIR_ACTION;
+ *   CHOOSE_FILE_ACTION -> FILE_CLOSE;
+ *   CHOOSE_FILE_ACTION -> FILE_APPEND;
+ *   CHOOSE_FILE_ACTION -> FILE_READ;
+ *   CHOOSE_FILE_ACTION -> FILE_SLEEP;
+ *   FILE_CLOSE -> CHOOSE_DIR_ACTION;
+ *   FILE_CLOSE -> ERROR;
+ *   FILE_APPEND -> CHOOSE_FILE_ACTION;
+ *   FILE_APPEND -> FILE_CLOSE_AND_UNLINK;
+ *   FILE_APPEND -> ERROR;
+ *   FILE_READ -> CHOOSE_FILE_ACTION;
+ *   FILE_READ -> ERROR;
+ *   FILE_SLEEP -> CHOOSE_FILE_ACTION;
+ *   FILE_CLOSE_AND_UNLINK -> CHOOSE_DIR_ACTION;
+ *   FILE_CLOSE_AND_UNLINK -> ERROR;
+ *   ERROR -> FORMAT;
+ *   FORMAT -> MOUNT;
+ *   FORMAT -> FINISH;
+ * }
+ */
+typedef enum {
+  CHOOSE_DIR_ACTION,
+  CHOOSE_FILE_ACTION,
+  DIR_CLOSE,
+  DIR_CREATE,
+  DIR_DELETE,
+  DIR_OPEN,
+  DIR_SLEEP,
+  ERROR,
+  FILE_APPEND,
+  FILE_READ,
+  FILE_CLOSE,
+  FILE_SLEEP,
+  FILE_CLOSE_AND_UNLINK,
+  FINISH,
+  FORMAT,
+  INIT,
+  INIT_ROOT,
+  MOUNT
+} test_state;
+
+typedef struct {
+  DIR *dir;
+  unsigned level;
+  unsigned content_count;
+  int fd;
+  int eno;
+  uint8_t buf [BUFFER_SIZE];
+  char file_path [MAXPATHLEN];
+} fs_state;
+
+static test_state do_format(
+  unsigned index,
+  fs_state *fs,
+  const char *disk_path,
+  const test_file_system_handler *handler,
+  void *handler_arg
+)
+{
+  int rv = 0;
+
+  printf("[%02u]: format: %s\n", index, disk_path);
+
+  rv = (*handler->format)(disk_path, handler_arg);
+  if (rv == 0) {
+    return MOUNT;
+  } else {
+    fs->eno = errno;
+
+    return FINISH;
+  }
+}
+
+static uint32_t simple_random(uint32_t v)
+{
+	v *= 1664525;
+	v += 1013904223;
+
+	return v;
+}
+
+static unsigned get_bucket_with_random(unsigned count, long random)
+{
+  long unsigned unit = (1U << 31) / count;
+  long unsigned bucket = (long unsigned) random / unit;
+
+  if (bucket != count) {
+    return bucket;
+  } else {
+    return bucket - 1;
+  }
+}
+
+static unsigned get_bucket(unsigned count)
+{
+  return get_bucket_with_random(count, lrand48());
+}
+
+static test_state do_choose_dir_action(void)
+{
+  switch (get_bucket(8)) {
+    case 0:
+    case 1:
+      return DIR_CLOSE;
+    case 2:
+    case 3:
+      return DIR_CREATE;
+    case 4:
+    case 5:
+      return DIR_OPEN;
+    case 6:
+      return DIR_DELETE;
+    case 7:
+      return DIR_SLEEP;
+    default:
+      assert(false);
+      break;
+  }
+}
+
+static test_state do_choose_file_action(void)
+{
+  switch (get_bucket(4)) {
+    case 0:
+      return FILE_CLOSE;
+    case 1:
+      return FILE_SLEEP;
+    case 2:
+      return FILE_APPEND;
+    case 3:
+      return FILE_READ;
+    default:
+      assert(false);
+      break;
+  }
+}
+
+static bool is_normal_entry(const char *entry_name)
+{
+  static const char *black_list [] = {
+    ".",
+    "..",
+    "lost+found"
+  };
+  size_t n = sizeof(black_list) / sizeof(black_list [0]);
+  size_t i = 0;
+  bool ok = true;
+
+  while (ok && i < n) {
+    ok = ok && strcmp(entry_name, black_list [i]) != 0;
+    ++i;
+  }
+
+  return ok;
+}
+
+static bool open_dir(fs_state *fs, const char *dir_path)
+{
+  int rv = 0;
+  bool change_dir = true;
+
+  if (dir_path == NULL) {
+    if (fs->level > 1) {
+      rv = chdir("..");
+      if (rv != 0) {
+        fs->eno = errno;
+
+        return false;
+      }
+
+      --fs->level;
+    } else {
+      return true;
+    }
+    dir_path = ".";
+    change_dir = false;
+  }
+
+  if (fs->dir != NULL) {
+    rv = closedir(fs->dir);
+    if (rv != 0) {
+      fs->eno = errno;
+
+      return false;
+    }
+  }
+
+  fs->content_count = 0;
+  fs->dir = opendir(dir_path);
+
+  if (fs->dir != NULL) {
+    struct dirent *de = NULL;
+
+    rewinddir(fs->dir);
+    while ((de = readdir(fs->dir)) != NULL) {
+      if (is_normal_entry(de->d_name)) {
+        ++fs->content_count;
+      }
+    }
+  } else {
+    fs->eno = errno;
+
+    return false;
+  }
+
+  if (change_dir) {
+    rv = chdir(dir_path);
+    if (rv != 0) {
+      fs->eno = errno;
+
+      return false;
+    }
+
+    ++fs->level;
+  }
+
+  return true;
+}
+
+static char *get_dir_entry(fs_state *fs, bool *is_dir)
+{
+  int rv = 0;
+  char *entry_name = NULL;
+
+  if (fs->content_count > 0) {
+    struct dirent *de = NULL;
+    unsigned bucket = get_bucket(fs->content_count);
+    unsigned i = 0;
+
+    rewinddir(fs->dir);
+    while ((de = readdir(fs->dir)) != NULL) {
+      if (is_normal_entry(de->d_name)) {
+        if (i != bucket) {
+          ++i;
+        } else {
+          break;
+        }
+      }
+    }
+
+    if (de != NULL) {
+      struct stat st;
+
+      rv = stat(de->d_name, &st);
+      if (rv == 0) {
+        *is_dir = S_ISDIR(st.st_mode);
+
+        entry_name = strdup(de->d_name);
+      }
+    }
+  }
+
+  return entry_name;
+}
+
+
+static test_state do_init_root(unsigned index, fs_state *fs, const char *mount_path)
+{
+  printf("[%02u]: init root: %s\n", index, mount_path);
+
+  if (open_dir(fs, mount_path)) {
+    return CHOOSE_DIR_ACTION;
+  } else {
+    return ERROR;
+  }
+}
+
+static test_state do_dir_close(unsigned index, fs_state *fs)
+{
+  if (fs->level > 1) {
+    printf("[%02u]: close dir\n", index);
+
+    if (open_dir(fs, NULL)) {
+      return CHOOSE_DIR_ACTION;
+    } else {
+      return ERROR;
+    }
+  } else {
+    return CHOOSE_DIR_ACTION;
+  }
+}
+
+static int open_file(fs_state *fs, const char *path, int flags, mode_t mode)
+{
+  size_t n = strlcpy(fs->file_path, path, sizeof(fs->file_path));
+  assert(n < sizeof(fs->file_path));
+
+  return open(fs->file_path, flags, mode);
+}
+
+static test_state do_dir_create(unsigned index, fs_state *fs)
+{
+  int rv = 0;
+  test_state state = ERROR;
+  long number = lrand48();
+  char name [64];
+
+  snprintf(name, sizeof(name), "%li", number);
+
+  if ((number % 2) == 0) {
+    printf("[%02u]: create file: %s\n", index, name);
+
+    rv = open_file(fs, name, O_RDONLY | O_CREAT, 0777);
+
+    if (rv >= 0) {
+      rv = close(rv);
+
+      if (rv == 0) {
+        state = CHOOSE_DIR_ACTION;
+      }
+    } else if (errno == ENOSPC) {
+      state = DIR_DELETE;
+    } else {
+      fs->eno = errno;
+    }
+  } else {
+    printf("[%02u]: create dir: %s\n", index, name);
+
+    rv = mkdir(name, 0777);
+
+    if (rv == 0) {
+      ++fs->content_count;
+
+      state = CHOOSE_DIR_ACTION;
+    } else if (errno == EEXIST) {
+      state = CHOOSE_DIR_ACTION;
+    } else if (errno == ENOSPC) {
+      state = DIR_DELETE;
+    } else {
+      fs->eno = errno;
+    }
+  }
+
+  return state;
+}
+
+static test_state remove_node(unsigned index, fs_state *fs, const char *path, bool is_dir)
+{
+  test_state state = ERROR;
+  int rv = 0;
+
+  if (is_dir) {
+    printf("[%02u]: remove dir: %s\n", index, path);
+
+    rv = rmdir(path);
+  } else {
+    printf("[%02u]: remove file: %s\n", index, path);
+
+    rv = unlink(path);
+  }
+
+  if (rv == 0) {
+    --fs->content_count;
+
+    state = CHOOSE_DIR_ACTION;
+  } else if (errno == ENOTEMPTY) {
+    state = CHOOSE_DIR_ACTION;
+  } else {
+    fs->eno = errno;
+  }
+
+  return state;
+}
+
+static test_state do_dir_delete(unsigned index, fs_state *fs)
+{
+  test_state state = ERROR;
+
+  if (fs->content_count > 0) {
+    bool is_dir = false;
+    char *dir_entry_path = get_dir_entry(fs, &is_dir);
+
+    if (dir_entry_path != NULL) {
+      state = remove_node(index, fs, dir_entry_path, is_dir);
+      free(dir_entry_path);
+    }
+  } else {
+    state = CHOOSE_DIR_ACTION;
+  }
+
+  return state;
+}
+
+static test_state do_dir_open(unsigned index, fs_state *fs)
+{
+  test_state state = ERROR;
+
+  if (fs->content_count > 0) {
+    bool is_dir = false;
+    char *dir_entry_path = get_dir_entry(fs, &is_dir);
+
+    if (dir_entry_path != NULL) {
+      if (is_dir) {
+        printf("[%02u]: open dir: %s\n", index, dir_entry_path);
+
+        if (open_dir(fs, dir_entry_path)) {
+          state = CHOOSE_DIR_ACTION;
+        }
+      } else {
+        printf("[%02u]: open file: %s\n", index, dir_entry_path);
+
+        fs->fd = open_file(fs, dir_entry_path, O_RDWR, 0);
+
+        if (fs->fd >= 0) {
+          state = CHOOSE_FILE_ACTION;
+        } else {
+          fs->eno = errno;
+        }
+      }
+
+      free(dir_entry_path);
+    }
+  } else {
+    state = CHOOSE_DIR_ACTION;
+  }
+
+  return state;
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+  #define VALUE_SHIFT_INIT 0
+  #define VALUE_SHIFT_INC 8
+#else
+  #define VALUE_SHIFT_INIT 24
+  #define VALUE_SHIFT_INC -8
+#endif
+
+static test_state do_file_read(unsigned index, fs_state *fs)
+{
+  test_state state = ERROR;
+  int fd = fs->fd;
+  off_t pos = lseek(fd, 0, SEEK_SET);
+  struct stat st;
+  int rv = fstat(fd, &st);
+  off_t file_size = st.st_size;
+
+  printf("[%02u]: read from file\n", index);
+
+  if (pos == 0 && rv == 0) {
+    if (file_size >= HEADER_SIZE) {
+      size_t remaining = (size_t) file_size;
+      size_t header = HEADER_SIZE;
+      size_t data = 0;
+      uint32_t header_buf [2];
+      uint8_t *header_pos = (uint8_t *) header_buf;
+      uint32_t value = 0;
+      unsigned value_shift = VALUE_SHIFT_INIT;
+
+      while (remaining > 0) {
+        size_t buf_size = sizeof(fs->buf);
+        size_t in = remaining < buf_size ? remaining : buf_size;
+        ssize_t in_actual = 0;
+        uint8_t *buf = fs->buf;
+
+        in_actual = read(fd, buf, in);
+        if (in_actual > 0) {
+          while (in_actual > 0) {
+            if (header > 0) {
+              size_t copy = header <= (size_t) in_actual ?
+                header : (size_t) in_actual;
+
+              memcpy(header_pos, buf, copy);
+
+              in_actual -= (ssize_t) copy;
+              remaining -= copy;
+              buf += copy;
+              header -= copy;
+              header_pos += copy;
+
+              if (header == 0) {
+                data = header_buf [0];
+                value = header_buf [1];
+                value_shift = VALUE_SHIFT_INIT;
+                value = simple_random(value);
+              }
+            }
+
+            if (data > 0) {
+              size_t compare = data <= (size_t) in_actual ?
+                data : (size_t) in_actual;
+              size_t c = 0;
+
+              for (c = 0; c < compare; ++c) {
+                assert(buf [c] == (uint8_t) (value >> value_shift));
+                value_shift = (value_shift + VALUE_SHIFT_INC) % 32;
+                if (value_shift == VALUE_SHIFT_INIT) {
+                  value = simple_random(value);
+                }
+              }
+
+              in_actual -= (ssize_t) compare;
+              remaining -= compare;
+              buf += compare;
+              data -= compare;
+
+              if (data == 0) {
+                header = HEADER_SIZE;
+                header_pos = (uint8_t *) header_buf;
+              }
+            }
+          }
+        } else if (in_actual == 0) {
+          /* This is either a severe bug or a damaged file system */
+          printf("[%02u]: error: invalid file size\n", index);
+          remaining = 0;
+        } else {
+          fs->eno = errno;
+          remaining = 0;
+        }
+      }
+
+      if (remaining == 0) {
+        state = CHOOSE_FILE_ACTION;
+      }
+    } else if (file_size == 0) {
+      state = CHOOSE_FILE_ACTION;
+    } else {
+      printf("[%02u]: error: unexpected file size\n", index);
+    }
+  } else {
+    fs->eno = errno;
+  }
+
+  return state;
+}
+
+static test_state do_file_append(unsigned index, fs_state *fs)
+{
+  test_state state = ERROR;
+  int fd = fs->fd;
+  off_t pos = lseek(fd, 0, SEEK_END);
+
+  printf("[%02u]: append to file\n", index);
+
+  if (pos != (off_t) -1) {
+    size_t buf_size = sizeof(fs->buf);
+    long random = lrand48();
+    size_t out = get_bucket_with_random(buf_size, random) + 1;
+    ssize_t out_actual = 0;
+    uint8_t *buf = fs->buf;
+    uint32_t value = (uint32_t) random;
+    uint32_t *words = (uint32_t *) &buf [0];
+    size_t word_count = 0;
+    size_t w = 0;
+
+    /* Must be big enough for the header */
+    out = out >= HEADER_SIZE ? out : HEADER_SIZE;
+
+    /*
+     * In case out is not an integral multiple of four we will write a bit to
+     * much.  This does not hurt since the buffer is big enough.
+     */
+    word_count = (out + 3) / 4;
+
+    /* The first word will contain the byte count with random data */
+    words [0] = out - HEADER_SIZE;
+
+    for (w = 1; w < word_count; ++w) {
+      words [w] = value;
+      value = simple_random(value);
+    }
+
+    out_actual = write(fd, buf, out);
+
+    if (out_actual == (ssize_t) out) {
+      state = CHOOSE_FILE_ACTION;
+    } else if (out_actual >= 0 || errno == ENOSPC) {
+      state = FILE_CLOSE_AND_UNLINK;
+    } else {
+      fs->eno = errno;
+    }
+  } else {
+    fs->eno = errno;
+  }
+
+  return state;
+}
+
+static test_state do_file_close(unsigned index, fs_state *fs)
+{
+  int rv = 0;
+  test_state state = ERROR;
+
+  printf("[%02u]: close file\n", index);
+
+  rv = close(fs->fd);
+  fs->fd = -1;
+
+  if (rv == 0) {
+    state = CHOOSE_DIR_ACTION;
+  } else {
+    fs->eno = errno;
+  }
+
+  return state;
+}
+
+static test_state do_file_close_and_unlink(unsigned index, fs_state *fs)
+{
+  test_state state = do_file_close(index, fs);
+
+  if (state != ERROR) {
+    state = remove_node(index, fs, fs->file_path, false);
+  }
+
+  return state;
+}
+
+static test_state do_sleep(unsigned index, test_state state)
+{
+  rtems_status_code sc = RTEMS_SUCCESSFUL;
+  rtems_interval ms = ((rtems_interval) get_bucket(10) + 1) * 100;
+  rtems_interval interval = ms / rtems_configuration_get_milliseconds_per_tick();
+
+  printf("[%02u]: sleep: %" PRIu32 " ms\n", index, ms);
+
+  sc = rtems_task_wake_after(interval);
+  ASSERT_SC(sc);
+
+  return state;
+}
+
+static test_state do_mount(
+  unsigned index,
+  fs_state *fs,
+  const char *disk_path,
+  const char *mount_path,
+  const test_file_system_handler *handler,
+  void *handler_arg
+)
+{
+  int rv = 0;
+
+  printf("[%02u]: mount: %s -> %s\n", index, disk_path, mount_path);
+
+  rv = (*handler->mount)(disk_path, mount_path, handler_arg);
+  if (rv == 0) {
+    return INIT_ROOT;
+  } else {
+    fs->eno = errno;
+
+    return FORMAT;
+  }
+}
+
+static test_state do_error(unsigned index, fs_state *fs, const char *mount_path)
+{
+  int rv = 0;
+
+  if (fs->eno > 0) {
+    printf("[%02u]: error: %s\n", index, strerror(fs->eno));
+  } else {
+    printf("[%02u]: error\n", index);
+  }
+  fs->eno = 0;
+
+  if (fs->fd >= 0) {
+    close(fs->fd);
+    fs->fd = -1;
+  }
+
+  if (fs->dir != NULL) {
+    closedir(fs->dir);
+    fs->dir = NULL;
+  }
+
+  chdir("/");
+  fs->level = 0;
+
+  rv = unmount(mount_path);
+  if (rv == 0) {
+    return FORMAT;
+  } else {
+    return FINISH;
+  }
+}
+
+void test_file_system_with_handler(
+  unsigned index,
+  const char *disk_path,
+  const char *mount_path,
+  const test_file_system_handler *handler,
+  void *handler_arg
+)
+{
+  int counter = 0;
+  test_state state = INIT;
+  fs_state *fs = calloc(1, sizeof(*fs));
+
+  if (fs == NULL) {
+    printf("[%02u]: not enough memory\n", index);
+    return;
+  }
+
+  fs->fd = -1;
+
+  printf("[%02u]: start\n", index);
+
+  while (state != FINISH && counter < 600) {
+    switch (state) {
+      case CHOOSE_DIR_ACTION:
+        state = do_choose_dir_action();
+        break;
+      case CHOOSE_FILE_ACTION:
+        state = do_choose_file_action();
+        break;
+      case DIR_CLOSE:
+        state = do_dir_close(index, fs);
+        break;
+      case DIR_CREATE:
+        state = do_dir_create(index, fs);
+        break;
+      case DIR_DELETE:
+        state = do_dir_delete(index, fs);
+        break;
+      case DIR_OPEN:
+        state = do_dir_open(index, fs);
+        break;
+      case DIR_SLEEP:
+        state = do_sleep(index, CHOOSE_DIR_ACTION);
+        break;
+      case ERROR:
+        state = do_error(index, fs, mount_path);
+        break;
+      case FILE_APPEND:
+        state = do_file_append(index, fs);
+        break;
+      case FILE_READ:
+        state = do_file_read(index, fs);
+        break;
+      case FILE_CLOSE:
+        state = do_file_close(index, fs);
+        break;
+      case FILE_CLOSE_AND_UNLINK:
+        state = do_file_close_and_unlink(index, fs);
+        break;
+      case FILE_SLEEP:
+        state = do_sleep(index, CHOOSE_FILE_ACTION);
+        break;
+      case FORMAT:
+        state = do_format(index, fs, disk_path, handler, handler_arg);
+        break;
+      case INIT:
+        state = MOUNT;
+        break;
+      case INIT_ROOT:
+        state = do_init_root(index, fs, mount_path);
+        break;
+      case MOUNT:
+        state = do_mount(
+          index,
+         fs,
+          disk_path,
+          mount_path,
+          handler,
+          handler_arg
+        );
+        break;
+      default:
+        assert(false);
+        break;
+    }
+
+    ++counter;
+  }
+
+  printf("[%02u]: finish\n", index);
+
+  free(fs);
+}
diff --git a/testsuites/libtests/flashdisk01/test-file-system.h b/testsuites/libtests/flashdisk01/test-file-system.h
new file mode 100644
index 0000000..f0894eb
--- /dev/null
+++ b/testsuites/libtests/flashdisk01/test-file-system.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010-2012 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Obere Lagerstr. 30
+ *  82178 Puchheim
+ *  Germany
+ *  <info 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.
+ */
+
+#ifndef TEST_FILE_SYSTEM_H
+#define TEST_FILE_SYSTEM_H
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef int (*test_file_system_mount_handler)(
+  const char *disk_path,
+  const char *mount_path,
+  void *arg
+);
+
+typedef int (*test_file_system_format_handler)(
+  const char *disk_path,
+  void *arg
+);
+
+typedef struct {
+  test_file_system_mount_handler mount;
+  test_file_system_format_handler format;
+} test_file_system_handler;
+
+void test_file_system_with_handler(
+  unsigned index,
+  const char *disk_path,
+  const char *mount_path,
+  const test_file_system_handler *handler,
+  void *handler_arg
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* TEST_FILE_SYSTEM_H */



More information about the rtems-vc mailing list