[PATCH v2 2/2] testsuites/jffs2: Add test for empty NOR FS

Kinsey Moore kinsey.moore at oarcorp.com
Tue Feb 20 04:29:55 UTC 2024


This adds a test to very that remounting a completely used, but empty
NOR JFFS2 filesystem is possible. Previously, this triggered an edge
condition in the JFFS2 scan code that prevented remount of a correctly
formed and uncorrupted filesystem.
---
 .../testsuites/fstests/fsjffs2empty01.yml     |  21 ++
 spec/build/testsuites/fstests/grp.yml         |   2 +
 .../fstests/fsjffs2empty01/fsjffs2empty01.doc |  11 +
 .../fstests/fsjffs2empty01/fsjffs2empty01.scn |   6 +
 testsuites/fstests/fsjffs2empty01/init.c      | 245 ++++++++++++++++++
 5 files changed, 285 insertions(+)
 create mode 100644 spec/build/testsuites/fstests/fsjffs2empty01.yml
 create mode 100644 testsuites/fstests/fsjffs2empty01/fsjffs2empty01.doc
 create mode 100644 testsuites/fstests/fsjffs2empty01/fsjffs2empty01.scn
 create mode 100644 testsuites/fstests/fsjffs2empty01/init.c

diff --git a/spec/build/testsuites/fstests/fsjffs2empty01.yml b/spec/build/testsuites/fstests/fsjffs2empty01.yml
new file mode 100644
index 0000000000..44d3f5fa23
--- /dev/null
+++ b/spec/build/testsuites/fstests/fsjffs2empty01.yml
@@ -0,0 +1,21 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-type: test-program
+cflags: []
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH & Co. KG
+cppflags: []
+cxxflags: []
+enabled-by: true
+features: c cprogram
+includes:
+- testsuites/fstests/jffs2_support
+ldflags: []
+links: []
+source:
+- testsuites/fstests/fsjffs2empty01/init.c
+stlib: []
+target: testsuites/fstests/fsjffs2empty01.exe
+type: build
+use-after: []
+use-before:
+- jffs2
diff --git a/spec/build/testsuites/fstests/grp.yml b/spec/build/testsuites/fstests/grp.yml
index 6c4d1a6fc9..a550ccbf9a 100644
--- a/spec/build/testsuites/fstests/grp.yml
+++ b/spec/build/testsuites/fstests/grp.yml
@@ -51,6 +51,8 @@ links:
   uid: fsimfsconfig03
 - role: build-dependency
   uid: fsimfsgeneric01
+- role: build-dependency
+  uid: fsjffs2empty01
 - role: build-dependency
   uid: fsjffs2gc01
 - role: build-dependency
diff --git a/testsuites/fstests/fsjffs2empty01/fsjffs2empty01.doc b/testsuites/fstests/fsjffs2empty01/fsjffs2empty01.doc
new file mode 100644
index 0000000000..2ad886a1fb
--- /dev/null
+++ b/testsuites/fstests/fsjffs2empty01/fsjffs2empty01.doc
@@ -0,0 +1,11 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: fsjffs2empty01
+
+directives:
+
+  - JFFS2 implementation
+
+concepts:
+
+  - Ensure that the JFFS2 library can remount a filesystem where every block has been written to and all files have been deleted.
diff --git a/testsuites/fstests/fsjffs2empty01/fsjffs2empty01.scn b/testsuites/fstests/fsjffs2empty01/fsjffs2empty01.scn
new file mode 100644
index 0000000000..56dca74761
--- /dev/null
+++ b/testsuites/fstests/fsjffs2empty01/fsjffs2empty01.scn
@@ -0,0 +1,6 @@
+*** BEGIN OF TEST FSJFFS2EMPTY 1 ***
+Initializing filesystem JFFS2
+
+
+Shutting down filesystem JFFS2
+*** END OF TEST FSJFFS2EMPTY 1 ***
diff --git a/testsuites/fstests/fsjffs2empty01/init.c b/testsuites/fstests/fsjffs2empty01/init.c
new file mode 100644
index 0000000000..3232ea8fde
--- /dev/null
+++ b/testsuites/fstests/fsjffs2empty01/init.c
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2024 On-Line Applications Research (OAR)
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <tmacros.h>
+
+#include <rtems.h>
+#include <rtems/jffs2.h>
+#include <rtems/libio.h>
+
+#define BLOCK_SIZE (16UL * 1024UL)
+
+#define FLASH_SIZE (8UL * BLOCK_SIZE)
+
+const char rtems_test_name[] = "FSJFFS2EMPTY 1";
+
+#define BASE_FOR_TEST "/mnt"
+static char big[] = BASE_FOR_TEST "/big";
+
+static char keg[523];
+
+static void init_keg(void)
+{
+  uint32_t v = 123;
+
+  for (size_t i = 0; i < sizeof(keg); ++i) {
+    v = v * 1664525 + 1013904223;
+    keg[i] = (uint8_t) (v >> 23);
+  }
+}
+
+static void create_big_file(void)
+{
+  int rv;
+  int fd = open(&big[0], O_WRONLY | O_TRUNC | O_CREAT,
+                S_IRWXU | S_IRWXG | S_IRWXO);
+  rtems_test_assert(fd >= 0);
+
+  for (int i = 0; i < 100; ++i) {
+    ssize_t n = write(fd, &keg[0], sizeof(keg));
+    rtems_test_assert(n == (ssize_t) sizeof(keg));
+  }
+
+  rv = close(fd);
+  rtems_test_assert(rv == 0);
+}
+
+static void remove_big_file(void)
+{
+  int rv = unlink(&big[0]);
+  rtems_test_assert(rv == 0);
+}
+
+typedef struct {
+  rtems_jffs2_flash_control super;
+  unsigned char area[FLASH_SIZE];
+} flash_control;
+
+static unsigned char *get_flash_chunk(rtems_jffs2_flash_control *super,
+                                      uint32_t offset)
+{
+  return &((flash_control *) super)->area[offset];
+}
+
+static int flash_read(
+  rtems_jffs2_flash_control *super,
+  uint32_t offset,
+  unsigned char *buffer,
+  size_t size_of_buffer
+)
+{
+  unsigned char *chunk = get_flash_chunk(super, offset);
+
+  memcpy(buffer, chunk, size_of_buffer);
+
+  return 0;
+}
+
+static int flash_write(
+  rtems_jffs2_flash_control *super,
+  uint32_t offset,
+  const unsigned char *buffer,
+  size_t size_of_buffer
+)
+{
+  unsigned char *chunk = get_flash_chunk(super, offset);
+
+  for (size_t i = 0; i < size_of_buffer; ++i) {
+    chunk[i] &= buffer[i];
+  }
+
+  return 0;
+}
+
+static int flash_erase(
+  rtems_jffs2_flash_control *super,
+  uint32_t offset
+)
+{
+  unsigned char *chunk = get_flash_chunk(super, offset);
+
+  memset(chunk, 0xff, BLOCK_SIZE);
+
+  return 0;
+}
+
+static flash_control flash_instance = {
+  .super = {
+    .block_size = BLOCK_SIZE,
+    .flash_size = FLASH_SIZE,
+    .read = flash_read,
+    .write = flash_write,
+    .erase = flash_erase
+  }
+};
+
+static rtems_jffs2_compressor_control compressor_instance = {
+  .compress = rtems_jffs2_compressor_rtime_compress,
+  .decompress = rtems_jffs2_compressor_rtime_decompress
+};
+
+static const rtems_jffs2_mount_data mount_data = {
+  .flash_control = &flash_instance.super,
+  .compressor_control = &compressor_instance
+};
+
+static void erase_all(void)
+{
+  memset(&flash_instance.area[0], 0xff, FLASH_SIZE);
+}
+
+static void test_initialize_filesystem(void)
+{
+  int rv = mount(
+    NULL,
+    BASE_FOR_TEST,
+    RTEMS_FILESYSTEM_TYPE_JFFS2,
+    RTEMS_FILESYSTEM_READ_WRITE,
+    &mount_data
+  );
+  rtems_test_assert(rv == 0);
+}
+
+static void test_shutdown_filesystem(void)
+{
+  int rv = unmount(BASE_FOR_TEST);
+  rtems_test_assert(rv == 0);
+}
+
+static rtems_task Init(
+    rtems_task_argument ignored)
+{
+  int rv;
+
+  TEST_BEGIN();
+
+  erase_all();
+
+  rv = mkdir(BASE_FOR_TEST, S_IRWXU | S_IRWXG | S_IRWXO);
+  rtems_test_assert(rv == 0);
+
+  puts( "Initializing JFFS2 filesystem" );
+  test_initialize_filesystem();
+
+  init_keg();
+
+  /*
+   * Ensure that jiffies != 0, to use most likely path in
+   * jffs2_mark_node_obsolete(). Without this the failure only happens
+   * intermittently.
+   */
+  while (rtems_clock_get_ticks_since_boot() == 0) {
+    /* Wait */
+  }
+
+  /*
+   * This must be done in 2 parts because the FS is only so large and all blocks
+   * must be written to.
+   */
+  create_big_file();
+  remove_big_file();
+
+  create_big_file();
+  remove_big_file();
+
+  puts( "\n\nShutting down JFFS2 filesystem");
+  test_shutdown_filesystem();
+
+  puts( "Initializing JFFS2 filesystem again" );
+  test_initialize_filesystem();
+
+  puts( "\n\nShutting down JFFS2 filesystem again" );
+  test_shutdown_filesystem();
+
+  TEST_END();
+  rtems_test_exit(0);
+}
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_FILESYSTEM_JFFS2
+
+#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 40
+
+#define CONFIGURE_MAXIMUM_TASKS 2
+
+#define CONFIGURE_INIT_TASK_STACK_SIZE (32 * 1024)
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
-- 
2.39.2



More information about the devel mailing list