2023-10-25 15:21:20 +02:00
|
|
|
======
|
2023-10-27 12:57:14 +02:00
|
|
|
CROMFS
|
2023-10-25 15:21:20 +02:00
|
|
|
======
|
|
|
|
|
|
|
|
Overview
|
|
|
|
========
|
|
|
|
|
|
|
|
This directory contains the the CROMFS file system. This is an in-memory
|
|
|
|
(meaning no block driver), read-only (meaning that can lie in FLASH) file
|
|
|
|
system. It uses LZF decompression on data only (meta data is not
|
|
|
|
compressed).
|
|
|
|
|
|
|
|
It accesses the in-memory file system via directory memory reads and, hence,
|
|
|
|
can only reside in random access NOR-like FLASH. It is intended for use
|
|
|
|
with on-chip FLASH available on most MCUs (the design could probably be
|
|
|
|
extended to access non-random-access FLASH as well, but those extensions
|
|
|
|
are not yet in place).
|
|
|
|
|
|
|
|
I do not have a good way to measure how much compression we get using LZF.
|
|
|
|
I have seen 37% compression reported in other applications, so I have to
|
|
|
|
accept that for now. That means, for example, that you could have a file
|
|
|
|
system with 512Kb of data in only 322Kb of FLASH, giving you 190Kb to do
|
|
|
|
other things with.
|
|
|
|
|
|
|
|
LZF compression is not known for its high compression ratios, but rather
|
|
|
|
for fast decompression. According to the author of the LZF decompression
|
|
|
|
routine, it is nearly as fast as a memcpy!
|
|
|
|
|
|
|
|
There is also a new tool at /tools/gencromfs.c that will generate binary
|
|
|
|
images for the NuttX CROMFS file system and and an example CROMFS file
|
|
|
|
system image at apps/examples/cromfs. That example includes a test file
|
|
|
|
system that looks like::
|
|
|
|
|
|
|
|
$ ls -Rl ../apps/examples/cromfs/cromfs
|
|
|
|
../apps/examples/cromfs/cromfs:
|
|
|
|
total 2
|
|
|
|
-rwxr--r--+ 1 spuda spuda 171 Mar 20 08:02 BaaBaaBlackSheep.txt
|
|
|
|
drwxrwxr-x+ 1 spuda spuda 0 Mar 20 08:11 emptydir
|
|
|
|
-rwxr--r--+ 1 spuda spuda 118 Mar 20 08:05 JackSprat.txt
|
|
|
|
drwxrwxr-x+ 1 spuda spuda 0 Mar 20 08:06 testdir1
|
|
|
|
drwxrwxr-x+ 1 spuda spuda 0 Mar 20 08:10 testdir2
|
|
|
|
drwxrwxr-x+ 1 spuda spuda 0 Mar 20 08:05 testdir3
|
|
|
|
../apps/examples/cromfs/cromfs/emptydir:
|
|
|
|
total 0
|
|
|
|
../apps/examples/cromfs/cromfs/testdir1:
|
|
|
|
total 2
|
|
|
|
-rwxr--r--+ 1 spuda spuda 249 Mar 20 08:03 DingDongDell.txt
|
|
|
|
-rwxr--r--+ 1 spuda spuda 247 Mar 20 08:06 SeeSawMargorieDaw.txt
|
|
|
|
../apps/examples/cromfs/cromfs/testdir2:
|
|
|
|
total 5
|
|
|
|
-rwxr--r--+ 1 spuda spuda 118 Mar 20 08:04 HickoryDickoryDock.txt
|
|
|
|
-rwxr--r--+ 1 spuda spuda 2082 Mar 20 08:10 TheThreeLittlePigs.txt
|
|
|
|
../apps/examples/cromfs/cromfs/testdir3:
|
|
|
|
total 1
|
|
|
|
-rwxr--r--+ 1 spuda spuda 138 Mar 20 08:05 JackBeNimble.txt
|
|
|
|
|
|
|
|
When built into NuttX and deployed on a target, it looks like::
|
|
|
|
|
|
|
|
NuttShell (NSH) NuttX-7.24
|
|
|
|
nsh> mount -t cromfs /mnt/cromfs
|
|
|
|
nsh> ls -Rl /mnt/cromfs
|
|
|
|
/mnt/cromfs:
|
|
|
|
dr-xr-xr-x 0 .
|
|
|
|
-rwxr--r-- 171 BaaBaaBlackSheep.txt
|
|
|
|
dr-xr-xr-x 0 emptydir/
|
|
|
|
-rwxr--r-- 118 JackSprat.txt
|
|
|
|
dr-xr-xr-x 0 testdir1/
|
|
|
|
dr-xr-xr-x 0 testdir2/
|
|
|
|
dr-xr-xr-x 0 testdir3/
|
|
|
|
/mnt/cromfs/emptydir:
|
|
|
|
drwxrwxr-x 0 .
|
|
|
|
dr-xr-xr-x 0 ..
|
|
|
|
/mnt/cromfs/testdir1:
|
|
|
|
drwxrwxr-x 0 .
|
|
|
|
dr-xr-xr-x 0 ..
|
|
|
|
-rwxr--r-- 249 DingDongDell.txt
|
|
|
|
-rwxr--r-- 247 SeeSawMargorieDaw.txt
|
|
|
|
/mnt/cromfs/testdir2:
|
|
|
|
drwxrwxr-x 0 .
|
|
|
|
dr-xr-xr-x 0 ..
|
|
|
|
-rwxr--r-- 118 HickoryDickoryDock.txt
|
|
|
|
-rwxr--r-- 2082 TheThreeLittlePigs.txt
|
|
|
|
/mnt/cromfs/testdir3:
|
|
|
|
drwxrwxr-x 0 .
|
|
|
|
dr-xr-xr-x 0 ..
|
|
|
|
-rwxr--r-- 138 JackBeNimble.txt
|
|
|
|
nsh>
|
|
|
|
|
|
|
|
Everything I have tried works: examining directories, catting files, etc.
|
|
|
|
The "." and ".." hard links also work::
|
|
|
|
|
|
|
|
nsh> cd /mnt/cromfs
|
|
|
|
nsh> cat emptydir/../testdir1/DingDongDell.txt
|
|
|
|
Ding, dong, bell,
|
|
|
|
Pussy's in the well.
|
|
|
|
Who put her in?
|
|
|
|
Little Johnny Green.
|
|
|
|
|
|
|
|
Who pulled her out?
|
|
|
|
Little Tommy Stout.
|
|
|
|
What a naughty boy was that,
|
|
|
|
To try to drown poor pussy cat,
|
|
|
|
Who never did him any harm,
|
|
|
|
And killed the mice in his father's barn.
|
|
|
|
|
|
|
|
nsh>
|
|
|
|
|
|
|
|
gencromfs
|
|
|
|
=========
|
|
|
|
|
|
|
|
The genromfs program can be found in tools/. It is a single C file called
|
|
|
|
gencromfs.c. It can be built in this way::
|
|
|
|
|
|
|
|
cd tools
|
|
|
|
make -f Makefile.host gencromfs
|
|
|
|
|
|
|
|
The genromfs tool used to generate CROMFS file system images. Usage is
|
|
|
|
simple::
|
|
|
|
|
|
|
|
gencromfs <dir-path> <out-file>
|
|
|
|
|
|
|
|
Where::
|
|
|
|
|
|
|
|
<dir-path> is the path to the directory will be at the root of the
|
|
|
|
new CROMFS file system image.
|
|
|
|
<out-file> the name of the generated, output C file. This file must
|
|
|
|
be compiled in order to generate the binary CROMFS file system
|
|
|
|
image.
|
|
|
|
|
|
|
|
All of these steps are automated in the apps/examples/cromfs/Makefile.
|
|
|
|
Refer to that Makefile as an reference.
|
|
|
|
|
|
|
|
Architecture
|
|
|
|
============
|
|
|
|
|
|
|
|
The CROMFS file system is represented by an in-memory data structure. This
|
|
|
|
structure is a "tree." At the root of the tree is a "volume node" that
|
|
|
|
describes the overall operating system. Other entities within the file
|
|
|
|
system are presented by other types of nodes: hard links, directories, and
|
|
|
|
files. These nodes are all described in fs/cromfs/cromfs.h.
|
|
|
|
|
|
|
|
In addition to general volume information, the volume node provides an
|
|
|
|
offset to the the "root directory". The root directory, like all other
|
|
|
|
CROMFS directories is simply a singly linked list of other nodes: hard link
|
|
|
|
nodes, directory nodes, and files. This list is managed by "peer offsets":
|
|
|
|
Each node in the directory contains an offset to its peer in the same
|
|
|
|
directory. This directory list is terminated with a zero offset.
|
|
|
|
|
|
|
|
The volume header lies at offset zero. Hence, any offset to a node or data
|
|
|
|
block can be converted to an absolute address in the in-memory CROMFS image
|
|
|
|
by simply adding that offset to the well-known address of the volume header.
|
|
|
|
|
|
|
|
Each hard link, directory, and file node in the directory list includes
|
|
|
|
such a "peer offset" to the next node in the list. Each node is followed
|
|
|
|
by the NUL-terminated name of the node. Each node also holds an additional
|
|
|
|
offset. Directory nodes contain a "child offset". That is, the offset to
|
|
|
|
the first entry in another singly linked list of nodes comprising the sub-
|
|
|
|
directory.
|
|
|
|
|
|
|
|
Hard link nodes hold the "link offset" to the node which is the target of
|
|
|
|
the link. The link offset may be an offset to another hard link node, to a
|
|
|
|
directory, or to a file node. The directory link offset would refer the
|
|
|
|
first node in singly linked directory list that represents the directory.
|
|
|
|
|
|
|
|
File nodes provide file data. The file name string is followed by a
|
|
|
|
variable length list of compressed data blocks. In this case each
|
|
|
|
compressed data block begins with an LZF header as described in
|
|
|
|
include/lzf.h.
|
|
|
|
|
|
|
|
So, given this description, we could illustrate the sample CROMFS file
|
|
|
|
system above with these nodes (where V=volume node, H=Hard link node,
|
|
|
|
D=directory node, F=file node, D=Data block)::
|
|
|
|
|
|
|
|
V
|
|
|
|
`- +- H: .
|
|
|
|
|
|
|
|
|
+- F: BaaBaaBlackSheep.txt
|
|
|
|
| `- D,D,D,...D
|
|
|
|
+- D: emptydir
|
|
|
|
| |- H: .
|
|
|
|
| `- H: ..
|
|
|
|
+- F: JackSprat.txt
|
|
|
|
| `- D,D,D,...D
|
|
|
|
+- D: testdir1
|
|
|
|
| |- H: .
|
|
|
|
| |- H: ..
|
|
|
|
| |- F: DingDongDell.txt
|
|
|
|
| | `- D,D,D,...D
|
|
|
|
| `- F: SeeSawMargorieDaw.txt
|
|
|
|
| `- D,D,D,...D
|
|
|
|
+- D: testdir2
|
|
|
|
| |- H: .
|
|
|
|
| |- H: ..
|
|
|
|
| |- F: HickoryDickoryDock.txt
|
|
|
|
| | `- D,D,D,...D
|
|
|
|
| `- F: TheThreeLittlePigs.txt
|
|
|
|
| `- D,D,D,...D
|
|
|
|
+- D: testdir3
|
|
|
|
|- H: .
|
|
|
|
|- H: ..
|
|
|
|
`- F: JackBeNimble.txt
|
|
|
|
`- D,D,D,...D
|
|
|
|
|
|
|
|
Where, for example::
|
|
|
|
|
|
|
|
H: ..
|
|
|
|
|
|
|
|
Represents a hard-link node with name ".."
|
|
|
|
|
|
|
|
|
|
|
|
|
+- D: testdir1
|
|
|
|
| |- H: .
|
|
|
|
|
|
|
|
Represents a directory node named "testdir1". The first node of the
|
|
|
|
directory list is a hard link with name "."
|
|
|
|
|
|
|
|
|
|
|
|
|
+- F: JackSprat.txt
|
|
|
|
| `- D,D,D,...D
|
|
|
|
|
|
|
|
Represents f file node named "JackSprat.txt" and is followed by some
|
|
|
|
sequence of compressed data blocks, D.
|
|
|
|
|
|
|
|
Configuration
|
|
|
|
=============
|
|
|
|
|
|
|
|
To build the CROMFS file system, you would add the following to your
|
|
|
|
configuration:
|
|
|
|
|
|
|
|
1. Enable LZF (The other LZF settings apply only to compression
|
|
|
|
and, hence, have no impact on CROMFS which only decompresses)::
|
|
|
|
|
|
|
|
CONFIG_LIBC_LZF=y
|
|
|
|
|
|
|
|
NOTE: This should be selected automatically when CONFIG_FS_CROMFS
|
|
|
|
is enabled.
|
|
|
|
|
|
|
|
2. Enable the CROMFS file system::
|
|
|
|
|
|
|
|
CONFIG_FS_CROMFS=y
|
|
|
|
|
|
|
|
3. Enable the apps/examples/cromfs example::
|
|
|
|
|
|
|
|
CONFIG_EXAMPLES_CROMFS=y
|
|
|
|
|
|
|
|
Or the apps/examples/elf example if you like::
|
|
|
|
|
|
|
|
CONFIG_ELF=y
|
|
|
|
# CONFIG_BINFMT_DISABLE is not set
|
|
|
|
CONFIG_EXAMPLES_ELF=y
|
|
|
|
CONFIG_EXAMPLES_ELF_CROMFS=y
|
|
|
|
|
|
|
|
Or implement your own custom CROMFS file system that example as a
|
|
|
|
guideline.
|