File system, RTEMS, RTOS, Software

Setting up YAFFS2 and JFFS2 on RTEMS with Flash Simulated on a RAM-Disk

Hi all, In this post, we’ll look forward to setting up flash file systems namely JFFS2 and YAFFS2 on RTEMS with flash simulated on a RAM-disk. For file system benchmarking purposes, we didn’t actually use them on a real flash(as to eliminate the effect of flash driver’s performance) but implementing them on a real flash won’t be very different from the process given in the later sections of this post. So, let’s begin with JFFS2 first:

JFFS2 on RTEMS

First reference you will see is of testsuites/fstests/jffs2_support/fs_support.c . Configuration here works up to a large extent unless the size of FLASH(configured via #define FLASH_SIZE (8UL * BLOCK_SIZE) ) increases beyond a certain limit.

typedef struct {
  rtems_jffs2_flash_control super;
  unsigned char area[FLASH_SIZE];
} flash_control;

Notice that in the above structure, the size of array statistically increases as FLASH_SIZE increases. Due to this, the final size of the binary also increases, and thus when loading it via u-boot, one can have the following error:

## Booting kernel from Legacy Image at 81500000 ...                                                                                   
   Image Name:   RTEMS                                                                                                                
   Created:      2018-08-05   3:48:17 UTC                                                                                             
   Image Type:   ARM Linux Kernel Image (gzip compressed)                                                                             
   Data Size:    1119071 Bytes = 1.1 MiB                                                                                              
   Load Address: 80000000                                                                                                             
   Entry Point:  80000000                                                                                                             
   Verifying Checksum ... OK                                                                                                          
## Flattened Device Tree blob at 88000000                                                                                             
   Booting using the fdt blob at 0x88000000                                                                                           
   Uncompressing Kernel Image ... Error: inflate() returned -5                                                                        
Image too large: increase CONFIG_SYS_BOOTM_LEN                                                                                        
Must RESET board to recover

In order to avoid it we can dynamically allocate the `area` array-like with :

flash_instance.area =  (char *)malloc(FLASH_SIZE + 1024);

Here, 1k extra space is allocated to compensate for the start alignment issues. So, below is my jffs2_support/fs_support.c file after modification:

/*
 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <info@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.org/license/LICENSE.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pmacros.h"

#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>

#include <rtems/jffs2.h>
#include <rtems/libio.h>
#include <rtems/libcsupport.h>

#include "fstest.h"
#include "fstest_support.h"

#define BLOCK_SIZE (16UL * 1024UL)

#define FLASH_SIZE (8UL * BLOCK_SIZE)

typedef struct {
  rtems_jffs2_flash_control super;
  unsigned char *area;
} flash_control;

static flash_control *get_flash_control(rtems_jffs2_flash_control *super)
{
  return (flash_control *) super;
}

static int flash_read(
  rtems_jffs2_flash_control *super,
  uint32_t offset,
  unsigned char *buffer,
  size_t size_of_buffer
)
{
  flash_control *self = get_flash_control(super);
  unsigned char *chunk = &self->area[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
)
{
  flash_control *self = get_flash_control(super);
  unsigned char *chunk = &self->area[offset];
  size_t i;

  for (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
)
{
  flash_control *self = get_flash_control(super);
  unsigned char *chunk = &self->area[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 rtems_resource_snapshot before_mount;

void test_initialize_filesystem(void)
{
  int rv;

  flash_instance.area =  (char *)malloc(FLASH_SIZE + 1024);
  erase_all();

  rv = mkdir(BASE_FOR_TEST, S_IRWXU | S_IRWXG | S_IRWXO);
  rtems_test_assert(rv == 0);

  rtems_resource_snapshot_take(&before_mount);

  rv = mount(
    NULL,
    BASE_FOR_TEST,
    RTEMS_FILESYSTEM_TYPE_JFFS2,
    RTEMS_FILESYSTEM_READ_WRITE,
    &mount_data
  );
  rtems_test_assert(rv == 0);
}

void test_shutdown_filesystem(void)
{
  int rv = unmount(BASE_FOR_TEST);
  rtems_test_assert(rv == 0);
  rtems_test_assert(rtems_resource_snapshot_check(&before_mount));
}

#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER

#define CONFIGURE_FILESYSTEM_JFFS2

#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 40

#define CONFIGURE_MAXIMUM_TASKS 1

#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_MAXIMUM_POSIX_KEY_VALUE_PAIRS 1

#define CONFIGURE_RTEMS_INIT_TASKS_TABLE

#define CONFIGURE_INIT
#include <rtems/confdefs.h>

Here, notice that flash_write(), flash_read, and flash_erase routines, which can be altered in case of reading/writing on an actual flash.

Setting up YAFFS2 on RTEMS

YAFFS configuration for RTEMS is a bit involved as it’s source files are kept in a separate repository https://github.com/m-labs/rtems-yaffs2

In order to use this port with RTEMS, we have to first build and install this library using the RTEMS toolchain. So, the first step will be:

  1. Setup an RTEMS toolchain along with the target BSP package:  This step is pretty straight forward for anyone familiar with RTEMS. You just have to use RSB and RTEMS to have the BSP(let’s say, BeagleBone Black).
  2. Clone the YAFFS port, build, install it: Grab the port and then setup the RTEMS_MAKEFILE_PATH variable like:
    export RTEMS_MAKEFILE_PATH=$sandbox/5/arm-rtems5/beagleboneblack

    where `$sandbox/5` is your toolchain install path. then build the port using Makefile.rtems

    cd rtems-yaffs2
    make -f Makefile.rtems install

After this step, we have the YAFFS library ready to be used. This can be used by using `-lyaffs2` the flag in the linker call.

The next step is to write an RTEMS configuration to use YAFFS2. Here’s the configuration( Christian Mauderer’s work) that can be used:

/*
 * Copyright (c) 2017 Christian Mauderer <oss@c-mauderer.de>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>

#include <rtems.h>
#include <rtems/console.h>
#include <rtems/shell.h>

#include "yaffs2.h"

#define RTEMS_FILESYSTEM_TYPE_YAFFS "yaffs"
#define MOUNT_PATH "/mnt"

static void
Init(rtems_task_argument arg)
{
	rtems_status_code sc;
	int rv;
	(void)arg;

	rv = mount_and_make_target_path(
			NULL,
			MOUNT_PATH,
			RTEMS_FILESYSTEM_TYPE_YAFFS,
			RTEMS_FILESYSTEM_READ_WRITE,
			NULL
		);
	assert(rv == 0);

	sc = rtems_shell_init(
		"SHLL",
		32*1024,
		RTEMS_MAXIMUM_PRIORITY - 10,
		CONSOLE_DEVICE_NAME,
		false,
		true,
		NULL
	);
	assert(sc == RTEMS_SUCCESSFUL);
}

/*
 * Configure RTEMS.
 */
#define CONFIGURE_MICROSECONDS_PER_TICK 1000

#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_STUB_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_ZERO_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK

#define CONFIGURE_FILESYSTEM_IMFS
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
#define CONFIGURE_HAS_OWN_FILESYSTEM_TABLE
#include <rtems/imfs.h>
const rtems_filesystem_table_t rtems_filesystem_table[] = {
	{ "/", IMFS_initialize_support },
	{ RTEMS_FILESYSTEM_TYPE_IMFS, IMFS_initialize },
	{ RTEMS_FILESYSTEM_TYPE_YAFFS, yaffs_initialize },
	{ NULL, NULL }
};
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 32

#define CONFIGURE_UNLIMITED_OBJECTS
#define CONFIGURE_UNIFIED_WORK_AREAS
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1

#define CONFIGURE_INIT_TASK_STACK_SIZE (64*1024)
#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT

#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE (32 * 1024)
#define CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS 4
#define CONFIGURE_BDBUF_CACHE_MEMORY_SIZE (1 * 1024 * 1024)
#define CONFIGURE_BDBUF_READ_AHEAD_TASK_PRIORITY 97
#define CONFIGURE_SWAPOUT_TASK_PRIORITY 97

//#define CONFIGURE_STACK_CHECKER_ENABLED

#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT

#include <rtems/confdefs.h>

/*
 * Configure Shell.
 */
#include <rtems/netcmds-config.h>
#include <bsp/irq-info.h>
#define CONFIGURE_SHELL_COMMANDS_INIT
#define CONFIGURE_SHELL_COMMANDS_ALL

#include <rtems/shellconfig.h>

and few supporting file:

/*
 * Based on code from Flickernoise
 * Copyright (C) 2010, 2011 Sebastien Bourdeauducq
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <assert.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/seterr.h>
#include <rtems/userenv.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <yaffs/rtems_yaffs.h>
#include <yaffs/yaffs_packedtags2.h>

#include "yaffs2.h"

#define MAXIMUM_YAFFS_MOUNTS 1

#define SIMFLASH_BLOCKSIZE (1024)
#define SIMFLASH_NR_BLOCKS (110*1024)
#define SIMFLASH_SIZE (SIMFLASH_BLOCKSIZE * SIMFLASH_NR_BLOCKS)

#define SIMFLASH_CHUNK_TAGS_SIZE (16)
#define SIMFLASH_CHUNK_DATA_SIZE (512-SIMFLASH_CHUNK_TAGS_SIZE)
#define SIMFLASH_CHUNK_WHOLE_SIZE (SIMFLASH_CHUNK_DATA_SIZE + SIMFLASH_CHUNK_TAGS_SIZE)

struct yaffs_softc {
	struct yaffs_dev *dev;
	uint8_t *simflash;
	unsigned int size;
	unsigned int blocksize;
	rtems_yaffs_os_handler free_os_context;
};

static rtems_status_code my_read(uint8_t *simflash, void *buffer, size_t len, size_t offset)
{
	memcpy(buffer, &simflash[offset], len);
	return RTEMS_SUCCESSFUL;
}

static rtems_status_code my_write(uint8_t *simflash, const void *buffer, size_t len, size_t offset)
{
	memcpy(&simflash[offset], buffer, len);
	return RTEMS_SUCCESSFUL;
}

/* Flash access functions */
static unsigned int chunk_address(struct yaffs_dev *dev, int c)
{
	struct yaffs_softc *sc = (struct yaffs_softc *)dev->driver_context;
	unsigned int chunks_per_block = (unsigned int) dev->param.chunks_per_block;
	return sc->blocksize*(c/chunks_per_block)
		+ SIMFLASH_CHUNK_WHOLE_SIZE*(c%chunks_per_block);
}

static int write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, const u8 *data, const struct yaffs_ext_tags *tags)
{
	struct yaffs_softc *sc = (struct yaffs_softc *)dev->driver_context;
	unsigned int address;
	
	//printf("%s %d (data=%p tags=%p)\n", __func__, nand_chunk, data, tags);
	address = chunk_address(dev, nand_chunk);
	if(data)
		my_write(sc->simflash, data, SIMFLASH_CHUNK_DATA_SIZE, address);
	if(tags) {
		struct yaffs_packed_tags2_tags_only x;
		yaffs_pack_tags2_tags_only(&x, tags);
		my_write(sc->simflash, &x, SIMFLASH_CHUNK_TAGS_SIZE,
		    address+SIMFLASH_CHUNK_DATA_SIZE);
	}
	return YAFFS_OK;
}

static int read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, u8 *data, struct yaffs_ext_tags *tags)
{
	struct yaffs_softc *sc = (struct yaffs_softc *)dev->driver_context;
	unsigned int address;
	
	//printf("%s %d (data=%p tags=%p)\n", __func__, nand_chunk, data, tags);
	address = chunk_address(dev, nand_chunk);
	if(data)
		my_read(sc->simflash, data, SIMFLASH_CHUNK_DATA_SIZE, address);
	if(tags) {
		struct yaffs_packed_tags2_tags_only x;
		my_read(sc->simflash, &x, SIMFLASH_CHUNK_TAGS_SIZE, address+SIMFLASH_CHUNK_DATA_SIZE);
		yaffs_unpack_tags2_tags_only(tags, &x);
	}
	return YAFFS_OK;
}

static int bad_block(struct yaffs_dev *dev, int blockId)
{
	struct yaffs_ext_tags tags;
	int chunk_nr;

	chunk_nr = blockId * dev->param.chunks_per_block;

	read_chunk_tags(dev, chunk_nr, NULL, &tags);
	tags.block_bad = 1;
	write_chunk_tags(dev, chunk_nr, NULL, &tags);
	
	return YAFFS_OK;
}

static int query_block(struct yaffs_dev *dev, int blockId, enum yaffs_block_state *state, u32 *seq_number)
{
	struct yaffs_ext_tags tags;
	int chunk_nr;

	*seq_number = 0;

	chunk_nr = blockId * dev->param.chunks_per_block;

	read_chunk_tags(dev, chunk_nr, NULL, &tags);
	if(tags.block_bad)
		*state = YAFFS_BLOCK_STATE_DEAD;
	else if(!tags.chunk_used)
		*state = YAFFS_BLOCK_STATE_EMPTY;
	else if(tags.chunk_used) {
		*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
		*seq_number = tags.seq_number;
	}
	
	return YAFFS_OK;
}

static int erase(struct yaffs_dev *dev, int blockId)
{
	struct yaffs_softc *sc = dev->driver_context;

	memset(&(sc->simflash[blockId * SIMFLASH_BLOCKSIZE]), 0xff,
	    SIMFLASH_BLOCKSIZE);

	return YAFFS_OK;
}

static int initialise(struct yaffs_dev *dev)
{
	struct yaffs_softc *sc = dev->driver_context;

	sc->simflash = malloc(SIMFLASH_SIZE);
	if (sc->simflash != 0) {
		memset(sc->simflash, 0xff, SIMFLASH_SIZE);
		return YAFFS_OK;
	} else {
		return YAFFS_FAIL;
	}
}

static int mount_sema_created;
static rtems_id mount_sema;
static struct yaffs_softc *current_mounts[MAXIMUM_YAFFS_MOUNTS];

static void unmount_handler(struct yaffs_dev *dev, void *os_context)
{
	struct yaffs_softc *softc = dev->driver_context;
	int i;

	rtems_semaphore_obtain(mount_sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);

	for(i=0;i<MAXIMUM_YAFFS_MOUNTS;i++) {
		if(current_mounts[i] == softc) {
			current_mounts[i] = NULL;
			break;
		}
	}

	softc->free_os_context(dev, os_context);
	free(softc);
	free(dev);

	rtems_semaphore_release(mount_sema);
}

static int flush_task_running;
static rtems_id flush_task_id;

static rtems_task flush_task(rtems_task_argument argument)
{
	int i;
	struct yaffs_softc *sc;
	rtems_yaffs_default_os_context *os_context;

	(void) argument;

	while(1) {
		rtems_task_wake_after(10*100);
		rtems_semaphore_obtain(mount_sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
		for(i=0;i<MAXIMUM_YAFFS_MOUNTS;i++) {
			sc = current_mounts[i];
			if(sc != NULL) {
				os_context = sc->dev->os_context;
				os_context->os_context.lock(sc->dev, os_context);
				yaffs_flush_whole_cache(sc->dev);
				os_context->os_context.unlock(sc->dev, os_context);
			}
		}
		rtems_semaphore_release(mount_sema);
	}
}

int yaffs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data)
{
	int i;
	int index;
	struct yaffs_dev *dev;
	struct yaffs_param *param;
	struct yaffs_softc *softc;
	rtems_yaffs_default_os_context *os_context;
	rtems_yaffs_mount_data md;
	rtems_status_code sc1, sc2;
	int r;
	
	if(!mount_sema_created) {
		sc1 = rtems_semaphore_create(
			rtems_build_name('Y', 'A', 'F', 'M'),
			1,
			RTEMS_LOCAL
				| RTEMS_BINARY_SEMAPHORE
				| RTEMS_INHERIT_PRIORITY
				| RTEMS_PRIORITY,
			0,
			&mount_sema
		);
		if(sc1 != RTEMS_SUCCESSFUL) {
			errno = ENOMEM;
			return -1;
		}
		mount_sema_created = 1;
	}
	
	rtems_semaphore_obtain(mount_sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
	index = -1;
	for(i=0;i<MAXIMUM_YAFFS_MOUNTS;i++) {
		if(current_mounts[i] == NULL) {
			index = i;
			break;
		}
	}
	rtems_semaphore_release(mount_sema);
	if(index == -1) {
		errno = ENOMEM;
		return -1;
	}
	
	dev = malloc(sizeof(struct yaffs_dev));
	if(dev == NULL) {
		errno = ENOMEM;
		return -1;
	}
	memset(dev, 0, sizeof(struct yaffs_dev));
	
	softc = malloc(sizeof(struct yaffs_softc));
	if(softc == NULL) {
		errno = ENOMEM;
		free(dev);
		return -1;
	}
	softc->dev = dev;
	
	softc->size = SIMFLASH_SIZE;
	softc->blocksize = SIMFLASH_BLOCKSIZE;
	if((sc1 != RTEMS_SUCCESSFUL)||(sc2 != RTEMS_SUCCESSFUL)) {
		errno = EIO;
		free(softc);
		free(dev);
		return -1;
	}
	
	os_context = malloc(sizeof(rtems_yaffs_default_os_context));
	if(os_context == NULL) {
		errno = ENOMEM;
		free(softc);
		free(dev);
		return -1;
	}
	r = rtems_yaffs_initialize_default_os_context(os_context);
	if(r == -1) {
		free(os_context);
		free(softc);
		free(dev);
		return -1;
	}
	softc->free_os_context = os_context->os_context.unmount;
	os_context->os_context.unmount = unmount_handler;
	
	/* set parameters */
	dev->driver_context = softc;
	dev->os_context = os_context;
	dev->read_only = 0;

	param = &(dev->param);
	param->name = "simyaffs2";
	
	param->start_block = 0;
	param->end_block = softc->size/softc->blocksize - 1;
	param->chunks_per_block = softc->blocksize/SIMFLASH_CHUNK_WHOLE_SIZE;
	param->total_bytes_per_chunk = SIMFLASH_CHUNK_WHOLE_SIZE;
	param->n_reserved_blocks = 5;
	param->n_caches = 15;
	param->inband_tags = 1;
	param->is_yaffs2 = 1;
	param->no_tags_ecc = 1;
	
	/* set callbacks */
	param->write_chunk_tags_fn = write_chunk_tags;
	param->read_chunk_tags_fn = read_chunk_tags;
	param->bad_block_fn = bad_block;
	param->query_block_fn = query_block;
	param->erase_fn = erase;
	param->initialise_flash_fn = initialise;
	
	md.dev = dev;
	r = rtems_yaffs_mount_handler(mt_entry, &md);
	if(r == -1) {
		errno = ENOMEM;
		softc->free_os_context(dev, os_context);
		free(softc);
		free(dev);
		return -1;
	}
	
	current_mounts[index] = softc;
	if(!flush_task_running) {
		sc1 = rtems_task_create(rtems_build_name('F', 'L', 'S', 'H'), 220, 256*1024,
			RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
			0, &flush_task_id);
		assert(sc1 == RTEMS_SUCCESSFUL);
		sc1 = rtems_task_start(flush_task_id, flush_task, 0);
		assert(sc1 == RTEMS_SUCCESSFUL);
		flush_task_running = 1;
	}
	
	return 0;
}
/*
 * Copyright (c) 2018 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * 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 AUTHOR 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 AUTHOR 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.
 */

#ifndef APP_YAFFS2_H
#define APP_YAFFS2_H

#include <rtems.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

int yaffs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* APP_YAFFS2_H */

Please notice that in yaffs.c file: there are two things Chunks and Blocks. Block is made up of smaller chunks. A Blocks is the smallest unit that can be erased while, chunks are the smallest units that can be read/written at a time. Also, one block is divided into two sections one for the flag and another for data.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.