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 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel