Chapter 56. The eCos configuration store

56.1. Overview

The eCos configuration store is a simple typed key/value store which uses NAND flash for its persistent storage.

The library is aimed at applications that wish to store simple configuration data without the overhead of a fully NAND-aware filesystem. It is also used by RedBoot to store persistent configuration data.

The following functionality is provided:

  • Write data
  • Read data
  • Erase individual data items
  • List and dump out store keys and contents (for debugging)

56.1.1. Design limitations

  • The data which may be stored is limited to a total of one NAND block, including the store's internal metadata.
  • The store is designed to be robust but simple. It is not expected to scale well; if there are a great many items in the store, read access will be slow.
  • The entire store is rewritten on every write; this means that write access to a busy store will similarly be slow.
  • The store is NAND-aware and incorporates simple wear-levelling logic but excessive numbers of writes will still risk burning out the NAND array. If the store is allocated only a small number of NAND blocks, this will exacerbate the effect. It is recommended to allow a reasonable number of blocks (5-10) to allow for blocks wearing out over the lifetime of the device.
  • Only simple locking is used to prevent corruption; all config store operations block until they are able to secure the protecting mutex.

56.2. Using the config store

The main entry points to the config store logic are as follows:

/* From <cyg/configstore/write.h>.
 * These functions write out a key, overwriting it if it is already there.
 * They return 0 for success or a negative errno value; see the header
 * file for details.
 */
externC
int cyg_configstore_write_int(const char *key, cyg_uint32 i);
externC
int cyg_configstore_write_bool(const char *key, cyg_bool b);
externC
int cyg_configstore_write_bytes(const char *key, void *src, cyg_uint32 len);
externC
int cyg_configstore_write_string(const char *key, const char *data);

/* Erases a single key */
externC
int cyg_configstore_erase_keystr(const char *key);
/* From <cyg/configstore/read.h>.
 * These functions read out a key or header.
 * They return 0 for success or a negative errno value; see the header
 * file for details. */

externC
int cyg_configstore_read_int(const char *key, cyg_uint32 *i);
externC
int cyg_configstore_read_bool(const char *key, cyg_bool *b);

/* Note:
* For bytes and strings, check *len_io after read to see the actual number
* of bytes read, INCLUDING the trailing NUL. */
externC
int cyg_configstore_read_bytes(const char *key, CYG_BYTE *buf, unsigned *len_io);
externC
int cyg_configstore_read_string(const char *key, char *buf, unsigned *len_io);

/* Reading out only the header allows you to check a key's type and size. */
externC
int cyg_configstore_read_header(const char *key, cyg_configstore_header_t *hdr);
/* From <cyg/configstore/util.h>. */

/* Lists all keys in the store (to diag_printf).
 * Not really machine-readable; intended for human-read debugging. */
externC
void cyg_configstore_list(void);

/* Dumps out everything in the store (to diag_printf).
 * Intended for human-read debugging.
 * NOTE: This may emit large amounts of output, which may
 * take an excessive length of time over a slow debug channel. */
externC
void cyg_configstore_dump(void);

For more details of the types and structures used, refer to <cyg/configstore/serialise.h> and <cyg/configstore/record.h> .

[Note]Note

Both store keys, and strings in the store, should not contain the ASCII NUL (0x00) character. Behaviour in this case is undefined.

56.2.1. Locking

The config store uses mutexes in order to prevent corruption by concurrent access. If CYGPKG_KERNEL is loaded in your eCos configuration, the config store automatically inherits the configured mutex behaviour.

56.2.2. Configuration

If the NAND array reports an error when writing or erasing a block, the config store will automatically retry the operation, up to CYGNUM_CONFIG_STORE_RETRIES times. The default setting is 3 retries.

The config store is allocated a single NAND partition. The device and partition are configured by the CDL options CYGDAT_CONFIG_STORE_DEVICE and CYGNUM_CONFIG_STORE_PARTITION. Normally CYGDAT_CONFIG_STORE_DEVICE is set by the platform HAL; CYGNUM_CONFIG_STORE_PARTITION may also be hard-wired, if RedBoot or other boot loader needs it.

To configure partition sizes, refer to the eCos HAL documents for your platform. It is recommended to allow a reasonable number of blocks (5-10) for the config store, in order to allow for blocks wearing out over the lifetime of the device.

[Caution]Caution
  1. If the config store is to be shared between multiple clients - for example, RedBoot and an application - the partition geometry must be configured identically to both of them. Be aware that changing the geometry in CDL will not update RedBoot unless you also reconfigure, rebuild and reflash it!
  2. If other applications write other data to the NAND array, care should be taken to not overwrite the config store. It is recommended to give them their own partition.

56.2.3. Storage details

The config store uses a single NAND block, conceptually contiguous from its component NAND pages but of course read and written a single page at a time.

The data block has the following contents:

  • Magic number CYG_CONFIGSTORE_MAGIC_HEADER .
  • Block serial number. These allow us to detect old versions and automatically clean them up. Serial Number Arithmetic (RFC1982) is used to compare.
  • Zero or more records, each introduced by the magic number CYG_CONFIGSTORE_MAGIC_RECORD.
  • Magic number CYG_CONFIGSTORE_MAGIC_FOOTER . This allows us to detect an incompletely-written block.

Every page written by the config store also contains magic numbers CYG_CONFIGSTORE_ECOS_TAG and CYG_CONFIGSTORE_MAGIC_TAG in the out-of-band (spare) area identifying it as belonging to the store. This allows us to attempt to be a tolerant neighbour and not erase data that appears to belong to another (possibly misconfigured) client of the NAND array.

Each record has the following contents:

  • The key. This is a null-terminated string to the user, though the null is not stored on NAND. This is stored in the same way as a string (see below).
  • The record type. This is one of Integer, Boolean, String or Bytes.
  • The length of the data.
  • The length of the data including padding.
  • The data itself.
  • Any padding required (see below).

56.2.4. Padding

Everything written is padded to the nearest 4-octet boundary.

  • Integers are always stored unsigned as 4 octets in host byte order.
  • Booleans are stored as integers with 1 mapping to True and 0 to False.
  • Strings and Bytes are stored as a tuple (data length, data, padding). The difference is that strings are null-terminated in RAM; the trailing null is stripped on write and restored on read.

56.2.5. Scanning

On every access, both read and write, the config block is scanned for consistency. Any obsoleted or incompletely-written blocks are automatically erased. When writing, the old block is only erased once the new block has been completely written.