Newtron Flash Filesystem (nffs)

Mynewt includes the Newtron Flash File System (nffs). This file system is designed with two priorities that makes it suitable for embedded use:

  • Minimal RAM usage

  • Reliability

Mynewt also provides an abstraction layer API (fs) to allow you to swap out nffs with a different file system of your choice.

Description

Areas

At the top level, an nffs disk is partitioned into areas. An area is a region of disk with the following properties:

  1. An area can be fully erased without affecting any other areas.

  2. Writing to one area does not restrict writes to other areas.

Regarding property 1: Generally, flash hardware divides its memory space into “blocks.” When erasing flash, entire blocks must be erased in a single operation; partial erases are not possible.

Regarding property 2: Furthermore, some flash hardware imposes a restriction with regards to writes: writes within a block must be strictly sequential. For example, if you wish to write to the first 16 bytes of a block, you must write bytes 1 through 15 before writing byte 16. This restriction only applies at the block level; writes to one block have no effect on what parts of other blocks can be written.

Thus, each area must comprise a discrete number of blocks.

Initialization

As part of overall system initialization, mynewt re-initialized the filesystem as follows:

  1. Restores an existing file system via detection.

  2. Creates a new file system via formatting.

A typical initialization sequence is the following:

  1. Detect an nffs file system in a specific region of flash.

  2. If no file system was detected, if configured to do so, format a new file system in the same flash region.

Note that in the latter case, the behavior is controlled with a variable in the syscfg.yml file. If NFFS_DETECT_FAIL is set to 1, the system ignores NFFS filesystem detection issues, but unless a new filesystem is formatted manually, all filesystem access will fail. If NFFS_DETECT_FAIL is set to 2, the system will format a new filesystem - note however this effectively deletes all existing data in the NFFS flash areas.

Both methods require the user to describe how the flash memory should be divided into nffs areas. This is accomplished with an array of struct nffs_area_desc configured as part of the BSP configureation.

After nffs has been initialized, the application can access the file system via the file system abstraction layer.

Data Structures

The fs/nffs package exposes the following data structures:

Struct

Description

struct nffs_area_desc

Descriptor for a single nffs area.

struct nffs_config

Configuration struct for nffs.

Miscellaneous measures

  • RAM usage:

    • 24 bytes per inode

    • 12 bytes per data block

    • 36 bytes per inode cache entry

    • 32 bytes per data block cache entry

  • Maximum filename size: 256 characters (no null terminator required)

  • Disallowed filename characters: / and \0

Internals

nffs implementation details can be found here:

Future enhancements

  • Error correction.

  • Encryption.

  • Compression.

API

Defines

NFFS_FILENAME_MAX_LEN
NFFS_MAX_AREAS

Functions

int nffs_init(void)
int nffs_detect(const struct nffs_area_desc *area_descs)
int nffs_format(const struct nffs_area_desc *area_descs)
int nffs_misc_desc_from_flash_area(int idx, int *cnt, struct nffs_area_desc *nad)

Variables

struct nffs_config nffs_config
struct nffs_config
#include <nffs.h>

Public Members

uint32_t nc_num_inodes

Maximum number of inodes; default=1024.

uint32_t nc_num_blocks

Maximum number of data blocks; default=4096.

uint32_t nc_num_files

Maximum number of open files; default=4.

uint32_t nc_num_dirs

Maximum number of open directories; default=4.

uint32_t nc_num_cache_inodes

Inode cache size; default=4.

uint32_t nc_num_cache_blocks

Data block cache size; default=64.

struct nffs_area_desc
#include <nffs.h>

Public Members

uint32_t nad_offset
uint32_t nad_length
uint8_t nad_flash_id