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:
- 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).
- 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.