From 07c833f8f98c665e2f7d7e9adfa5f5503177dbff Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 19 Dec 2016 09:54:16 +0100 Subject: JFFS2: Add RTEMS_JFFS2_GET_INFO Add IO control RTEMS_JFFS2_GET_INFO to get some JFFS2 filesystem instance information. Update #2844. --- cpukit/libfs/src/jffs2/include/rtems/jffs2.h | 102 +++++++++- cpukit/libfs/src/jffs2/src/fs-rtems.c | 74 +++++++- testsuites/fstests/Makefile.am | 1 + testsuites/fstests/configure.ac | 1 + testsuites/fstests/fsjffs2gc01/Makefile.am | 29 +++ testsuites/fstests/fsjffs2gc01/fsjffs2gc01.doc | 11 ++ testsuites/fstests/fsjffs2gc01/fsjffs2gc01.scn | 6 + testsuites/fstests/fsjffs2gc01/init.c | 251 +++++++++++++++++++++++++ 8 files changed, 470 insertions(+), 5 deletions(-) create mode 100644 testsuites/fstests/fsjffs2gc01/Makefile.am create mode 100644 testsuites/fstests/fsjffs2gc01/fsjffs2gc01.doc create mode 100644 testsuites/fstests/fsjffs2gc01/fsjffs2gc01.scn create mode 100644 testsuites/fstests/fsjffs2gc01/init.c diff --git a/cpukit/libfs/src/jffs2/include/rtems/jffs2.h b/cpukit/libfs/src/jffs2/include/rtems/jffs2.h index 7b2f4d5de2..39c9420e62 100644 --- a/cpukit/libfs/src/jffs2/include/rtems/jffs2.h +++ b/cpukit/libfs/src/jffs2/include/rtems/jffs2.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * Copyright (c) 2013, 2016 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -17,6 +17,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -455,6 +456,105 @@ int rtems_jffs2_initialize( const void *data ); +/** + * @brief JFFS2 filesystem instance information. + * + * @see RTEMS_JFFS2_GET_INFO. + */ +typedef struct { + /** + * @brief Flash size in bytes. + */ + uint32_t flash_size; + + /** + * @brief Count of flash blocks (eraseable units). + */ + uint32_t flash_blocks; + + /** + * @brief Size of a flash block in bytes. + */ + uint32_t flash_block_size; + + /** + * @brief Used size in bytes. + * + * Used areas contain valid data. + */ + uint32_t used_size; + + /** + * @brief Dirty size in bytes. + * + * Used areas contain no longer used data. + */ + uint32_t dirty_size; + + /** + * @brief Wasted size in bytes. + * + * Wasted areas are unusable. + */ + uint32_t wasted_size; + + /** + * @brief Free size in bytes. + * + * Free areas may be used to store new data. + */ + uint32_t free_size; + + /** + * @brief Bad size in bytes. + * + * Bad areas indicate damaged flash blocks. + */ + uint32_t bad_size; + + /** + * @brief Count of clean blocks. + * + * Clean blocks contain only used areas. + */ + uint32_t clean_blocks; + + /** + * @brief Count of dirty blocks. + * + * Dirty blocks contain dirty and used areas. + */ + uint32_t dirty_blocks; + + /** + * @brief Count of erasable blocks. + * + * Erase blocks contain only dirty or wasted areas. + */ + uint32_t erasable_blocks; + + /** + * @brief Count of free blocks. + * + * Free blocks contain a free area. + */ + uint32_t free_blocks; + + /** + * @brief Count of bad blocks. + * + * Bad blocks are damaged. + */ + uint32_t bad_blocks; +} rtems_jffs2_info; + +/** + * @brief IO control to get the JFFS2 filesystem instance information. + * + * @see rtems_jffs2_info. + */ +#define RTEMS_JFFS2_GET_INFO _IOR('F', 1, rtems_jffs2_info) + /** @} */ #ifdef __cplusplus diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c index ce84d44470..c8045dbed7 100644 --- a/cpukit/libfs/src/jffs2/src/fs-rtems.c +++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c @@ -4,7 +4,7 @@ * Copyright © 2001-2003 Free Software Foundation, Inc. * Copyright © 2001-2007 Red Hat, Inc. * Copyright © 2004-2010 David Woodhouse - * Copyright © 2013 embedded brains GmbH + * Copyright © 2013, 2016 embedded brains GmbH * * Created by Dominic Ostrowski * Contributors: David Woodhouse, Nick Garnett, Richard Panton. @@ -512,12 +512,78 @@ static ssize_t rtems_jffs2_dir_read(rtems_libio_t *iop, void *buf, size_t len) } } +static uint32_t rtems_jffs2_count_blocks(const struct list_head *list) +{ + uint32_t count = 0; + struct jffs2_eraseblock *jeb; + + list_for_each_entry(jeb, list, list) { + ++count; + } + + return count; +} + +static void rtems_jffs2_get_info( + const struct jffs2_sb_info *c, + rtems_jffs2_info *info +) +{ + info->flash_size = c->flash_size; + info->flash_blocks = c->nr_blocks; + info->flash_block_size = c->sector_size; + info->used_size = c->used_size; + info->dirty_size = c->dirty_size; + info->wasted_size = c->wasted_size; + info->free_size = c->free_size; + info->bad_size = c->bad_size; + info->clean_blocks = rtems_jffs2_count_blocks(&c->clean_list); + info->dirty_blocks = rtems_jffs2_count_blocks(&c->very_dirty_list) + + rtems_jffs2_count_blocks(&c->dirty_list); + info->dirty_blocks += c->gcblock != NULL; + info->erasable_blocks = rtems_jffs2_count_blocks(&c->erasable_list) + + rtems_jffs2_count_blocks(&c->erasable_pending_wbuf_list) + + rtems_jffs2_count_blocks(&c->erasing_list) + + rtems_jffs2_count_blocks(&c->erase_checking_list) + + rtems_jffs2_count_blocks(&c->erase_pending_list) + + rtems_jffs2_count_blocks(&c->erase_complete_list); + info->free_blocks = rtems_jffs2_count_blocks(&c->free_list); + info->free_blocks += c->nextblock != NULL; + info->bad_blocks = rtems_jffs2_count_blocks(&c->bad_list); +} + +static int rtems_jffs2_ioctl( + rtems_libio_t *iop, + ioctl_command_t request, + void *buffer +) +{ + struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop); + int eno; + + rtems_jffs2_do_lock(inode->i_sb); + + switch (request) { + case RTEMS_JFFS2_GET_INFO: + rtems_jffs2_get_info(&inode->i_sb->jffs2_sb, buffer); + eno = 0; + break; + default: + eno = EINVAL; + break; + } + + rtems_jffs2_do_unlock(inode->i_sb); + + return rtems_jffs2_eno_to_rv_and_errno(eno); +} + static const rtems_filesystem_file_handlers_r rtems_jffs2_directory_handlers = { .open_h = rtems_filesystem_default_open, .close_h = rtems_filesystem_default_close, .read_h = rtems_jffs2_dir_read, .write_h = rtems_filesystem_default_write, - .ioctl_h = rtems_filesystem_default_ioctl, + .ioctl_h = rtems_jffs2_ioctl, .lseek_h = rtems_filesystem_default_lseek_directory, .fstat_h = rtems_jffs2_fstat, .ftruncate_h = rtems_filesystem_default_ftruncate_directory, @@ -659,7 +725,7 @@ static const rtems_filesystem_file_handlers_r rtems_jffs2_file_handlers = { .close_h = rtems_filesystem_default_close, .read_h = rtems_jffs2_file_read, .write_h = rtems_jffs2_file_write, - .ioctl_h = rtems_filesystem_default_ioctl, + .ioctl_h = rtems_jffs2_ioctl, .lseek_h = rtems_filesystem_default_lseek_file, .fstat_h = rtems_jffs2_fstat, .ftruncate_h = rtems_jffs2_file_ftruncate, @@ -677,7 +743,7 @@ static const rtems_filesystem_file_handlers_r rtems_jffs2_link_handlers = { .close_h = rtems_filesystem_default_close, .read_h = rtems_filesystem_default_read, .write_h = rtems_filesystem_default_write, - .ioctl_h = rtems_filesystem_default_ioctl, + .ioctl_h = rtems_jffs2_ioctl, .lseek_h = rtems_filesystem_default_lseek, .fstat_h = rtems_jffs2_fstat, .ftruncate_h = rtems_filesystem_default_ftruncate, diff --git a/testsuites/fstests/Makefile.am b/testsuites/fstests/Makefile.am index 930fbd7254..0edd25947c 100644 --- a/testsuites/fstests/Makefile.am +++ b/testsuites/fstests/Makefile.am @@ -1,6 +1,7 @@ ACLOCAL_AMFLAGS = -I ../aclocal _SUBDIRS = +_SUBDIRS += fsjffs2gc01 _SUBDIRS += fsimfsconfig03 _SUBDIRS += fsimfsconfig02 _SUBDIRS += fsimfsconfig01 diff --git a/testsuites/fstests/configure.ac b/testsuites/fstests/configure.ac index f0bbaafdbd..7d00ba7349 100644 --- a/testsuites/fstests/configure.ac +++ b/testsuites/fstests/configure.ac @@ -77,6 +77,7 @@ AC_CHECK_SIZEOF([blkcnt_t]) # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile +fsjffs2gc01/Makefile fsimfsconfig03/Makefile fsimfsconfig02/Makefile fsimfsconfig01/Makefile diff --git a/testsuites/fstests/fsjffs2gc01/Makefile.am b/testsuites/fstests/fsjffs2gc01/Makefile.am new file mode 100644 index 0000000000..e0571f48bf --- /dev/null +++ b/testsuites/fstests/fsjffs2gc01/Makefile.am @@ -0,0 +1,29 @@ +rtems_tests_PROGRAMS = fsjffs2gc01 +fsjffs2gc01_SOURCES = init.c +fsjffs2gc01_SOURCES += ../support/fstest_support.c +fsjffs2gc01_SOURCES += ../support/fstest_support.h +fsjffs2gc01_SOURCES += ../support/fstest.h +fsjffs2gc01_SOURCES += ../../psxtests/include/pmacros.h +fsjffs2gc01_SOURCES += ../jffs2_support/fs_support.c +fsjffs2gc01_SOURCES += ../jffs2_support/fs_config.h +fsjffs2gc01_LDADD = -ljffs2 + +dist_rtems_tests_DATA = fsjffs2gc01.scn fsjffs2gc01.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/support +AM_CPPFLAGS += -I$(top_srcdir)/jffs2_support +AM_CPPFLAGS += -I$(top_srcdir)/../support/include +AM_CPPFLAGS += -I$(top_srcdir)/../psxtests/include + +LINK_OBJS = $(fsjffs2gc01_OBJECTS) $(fsjffs2gc01_LDADD) +LINK_LIBS = $(fsjffs2gc01_LDLIBS) + +fsjffs2gc01$(EXEEXT): $(fsjffs2gc01_OBJECTS) $(fsjffs2gc01_DEPENDENCIES) + @rm -f fsjffs2gc01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/fstests/fsjffs2gc01/fsjffs2gc01.doc b/testsuites/fstests/fsjffs2gc01/fsjffs2gc01.doc new file mode 100644 index 0000000000..53e71a4797 --- /dev/null +++ b/testsuites/fstests/fsjffs2gc01/fsjffs2gc01.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: fsjffs2gc01 + +directives: + + - JFFS2 implementation + +concepts: + + - Ensure that RTEMS_JFFS2_GET_INFO returns the expected information. diff --git a/testsuites/fstests/fsjffs2gc01/fsjffs2gc01.scn b/testsuites/fstests/fsjffs2gc01/fsjffs2gc01.scn new file mode 100644 index 0000000000..7747e8dee8 --- /dev/null +++ b/testsuites/fstests/fsjffs2gc01/fsjffs2gc01.scn @@ -0,0 +1,6 @@ +*** BEGIN OF TEST FSJFFS2GC 1 *** +Initializing filesystem JFFS2 + + +Shutting down filesystem JFFS2 +*** END OF TEST FSJFFS2GC 1 *** diff --git a/testsuites/fstests/fsjffs2gc01/init.c b/testsuites/fstests/fsjffs2gc01/init.c new file mode 100644 index 0000000000..df2e986412 --- /dev/null +++ b/testsuites/fstests/fsjffs2gc01/init.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include + +const char rtems_test_name[] = "FSJFFS2GC 1"; + +static const rtems_jffs2_info info_initial = { + .flash_size = 131072, + .flash_blocks = 8, + .flash_block_size = 16384, + .used_size = 96, + .dirty_size = 0, + .wasted_size = 0, + .free_size = 130976, + .bad_size = 0, + .clean_blocks = 0, + .dirty_blocks = 0, + .erasable_blocks = 0, + .free_blocks = 8, + .bad_blocks = 0 +}; + +static const rtems_jffs2_info info_big_created = { + .flash_size = 131072, + .flash_blocks = 8, + .flash_block_size = 16384, + .used_size = 22292, + .dirty_size = 0, + .wasted_size = 164, + .free_size = 108616, + .bad_size = 0, + .clean_blocks = 1, + .dirty_blocks = 0, + .erasable_blocks = 0, + .free_blocks = 7, + .bad_blocks = 0 +}; + +static const rtems_jffs2_info info_big_removed = { + .flash_size = 131072, + .flash_blocks = 8, + .flash_block_size = 16384, + .used_size = 72, + .dirty_size = 16384, + .wasted_size = 6000, + .free_size = 108616, + .bad_size = 0, + .clean_blocks = 0, + .dirty_blocks = 0, + .erasable_blocks = 1, + .free_blocks = 7, + .bad_blocks = 0 +}; + +static const rtems_jffs2_info info_more_files_created = { + .flash_size = 131072, + .flash_blocks = 8, + .flash_block_size = 16384, + .used_size = 54896, + .dirty_size = 23336, + .wasted_size = 36, + .free_size = 52804, + .bad_size = 0, + .clean_blocks = 2, + .dirty_blocks = 1, + .erasable_blocks = 1, + .free_blocks = 4, + .bad_blocks = 0 +}; + +static const rtems_jffs2_info info_some_files_removed = { + .flash_size = 131072, + .flash_blocks = 8, + .flash_block_size = 16384, + .used_size = 23528, + .dirty_size = 47372, + .wasted_size = 7368, + .free_size = 52804, + .bad_size = 0, + .clean_blocks = 0, + .dirty_blocks = 3, + .erasable_blocks = 1, + .free_blocks = 4, + .bad_blocks = 0 +}; + +static char big[] = "big"; + +static const char * const more[] = { + "1", + "2", + "3", + "4", + "5", + "6", + "7" +}; + +#define ASSERT_INFO(a, b) do { \ + rv = ioctl(fd, RTEMS_JFFS2_GET_INFO, &info); \ + rtems_test_assert(rv == 0); \ + rtems_test_assert(memcmp(a, b, sizeof(*a)) == 0); \ +} while (0) + +static const mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + +static char keg[523]; + +static uint32_t simple_random(uint32_t v) +{ + v *= 1664525; + v += 1013904223; + + return v; +} + +static void init_keg(void) +{ + size_t i; + uint32_t v; + + v = 123; + for (i = 0; i < sizeof(keg); ++i) { + v = simple_random(v); + keg[i] = (uint8_t) (v >> 23); + } +} + +static void write_kegs(int fd, int kegs) +{ + int i; + + for (i = 0; i < kegs; ++i) { + ssize_t n; + + n = write(fd, &keg[0], sizeof(keg)); + rtems_test_assert(n == (ssize_t) sizeof(keg)); + } +} + +static void create_big_file(void) +{ + int fd; + int rv; + + fd = open(&big[0], O_WRONLY | O_TRUNC | O_CREAT, mode); + rtems_test_assert(fd >= 0); + + write_kegs(fd, 37); + + rv = close(fd); + rtems_test_assert(rv == 0); +} + +static void remove_big_file(void) +{ + int rv; + + rv = unlink(&big[0]); + rtems_test_assert(rv == 0); +} + +static void create_more_files(void) +{ + int fds[RTEMS_ARRAY_SIZE(more)]; + int rv; + size_t i; + int j; + + for (i = 0; i < RTEMS_ARRAY_SIZE(fds); ++i) { + fds[i] = open(more[i], O_WRONLY | O_TRUNC | O_CREAT, mode); + rtems_test_assert(fds[i] >= 0); + } + + for (j = 0; j < 13; ++j) { + for (i = 0; i < RTEMS_ARRAY_SIZE(fds); ++i) { + write_kegs(fds[i], 1); + } + } + + for (i = 0; i < RTEMS_ARRAY_SIZE(fds); ++i) { + rv = close(fds[i]); + rtems_test_assert(rv == 0); + } +} + +static void remove_some_files(void) +{ + size_t i; + + for (i = 0; i < RTEMS_ARRAY_SIZE(more); i += 2) { + int rv; + + rv = unlink(more[i]); + rtems_test_assert(rv == 0); + } +} + +void test(void) +{ + int fd; + int rv; + rtems_jffs2_info info; + + init_keg(); + + fd = open("/", O_RDONLY); + rtems_test_assert(fd >= 0); + + ASSERT_INFO(&info, &info_initial); + + create_big_file(); + ASSERT_INFO(&info, &info_big_created); + + remove_big_file(); + ASSERT_INFO(&info, &info_big_removed); + + create_more_files(); + ASSERT_INFO(&info, &info_more_files_created); + + remove_some_files(); + ASSERT_INFO(&info, &info_some_files_removed); + + rv = close(fd); + rtems_test_assert(rv == 0); +} -- cgit v1.2.3