casaroli opened a new pull request, #3665:
URL: https://github.com/apache/nuttx-apps/pull/3665
## Summary
The applications that go with **XIPFS**, the writable execute-in-place file
system added in the companion PR:
**Companion PR: apache/nuttx#19536**
This one depends on that one and cannot be built without it: every Kconfig
option here depends on `CONFIG_FS_XIPFS`.
Three additions:
* **`system/xipfs`** — a command that compacts a volume and reports how its
erase blocks are laid out. Because a XIPFS file is a single contiguous
extent, an allocation can fail for lack of a contiguous run while plenty of
free space remains, and compaction is never automatic: the file system
returns `-ENOSPC` and the caller decides. This command is that decision
made
by hand. `-n` surveys without moving anything and prints the per-file
table,
a block map, and the share of free space a single allocation cannot reach —
which is the number a caller facing `-ENOSPC` actually wants. The pass is
asked for through a descriptor for the mountpoint directory, so no file is
held open while it runs and one pass reaches every extent.
* **`testing/fs/xipfs`** — the test suite, 14 sections selectable by name
because the power-loss sweeps run for minutes while everything else runs in
seconds. Beyond the routine VFS paths it aims at the properties that are
easy to get wrong and quiet when they are: that a pin taken by a task that
then *dies without unmapping* is still released, and that failing the Nth
flash operation and remounting always yields a consistent volume with every
committed file intact. The sweeps cover create, unlink, mkdir/rmdir and
defragmentation, each with the failing operation left torn as well as
cleanly refused.
* **`examples/nxflatxip`** — the end-to-end demonstration: write an NXFLAT
module into the volume at run time the way a download would, confirm the
file system hands out a real flash pointer for it, and run two instances
concurrently. Both report the same text address, inside the flash window,
while their stacks differ. Two subcommands cover the file system rather
than
the module: `bench` times a bulk read out of mapped flash before and after
a
write, and `defrag` fragments the volume until an allocation genuinely
cannot be satisfied, compacts, retries, then verifies every relocated file
byte-for-byte and again after a remount.
### A note on the demo module
The module is built in-tree exactly the way `examples/nxflat` builds its test
programs, so it needs the same two host tools, `mknxflat` and `ldnxflat`.
It deliberately has **no static data and no string constants**, and reports
through a callback into the firmware instead of formatting its own output.
That is not stylistic. The `ldnxflat` in circulation resolves the GOT entries
for `.bss` objects into the import table — so the module overwrites the
addresses of the functions it imports and branches into nothing on its next
call out — and drops the addend already in the instruction when resolving the
PC-relative references to `.rodata`, so every string pointer lands in the
middle of the code. Both were diagnosed on hardware; the comment at the top
of
`module/xipmod.c` records them. The callback also exercises the other
direction of the interface: firmware code entered with the module's data base
still live in its PIC register.
## Impact
* **New applications, all off by default**, and all depending on
`CONFIG_FS_XIPFS`, so nothing changes for existing configurations.
* `examples/nxflatxip` additionally depends on `NXFLAT` and `LIBC_EXECFUNCS`,
and its build needs `mknxflat`/`ldnxflat` and a board `Make.defs` that
names
them — the same requirement `examples/nxflat` already has.
* `testing/fs/xipfs` writes and erases its volume continuously, the
power-loss
sections most of all. The Kconfig help and the documentation both say to
point it at a volume whose contents do not matter.
* No existing file is modified.
## Testing
Host: macOS 15 (arm64), `arm-none-eabi-gcc 14.2.rel1`.
Targets:
* `sim:xipfs` — XIPFS on `rammtd`.
* `pimoroni-pico-2-plus:xipfs` — XIPFS on real QSPI NOR via `/dev/rpflash`.
Every hardware run was bracketed by a `uname -a` check of the git revision
and
board name, before the first command and after the last, so the logs cannot
be
from a different build.
### Full suite on real flash
```
[identity ok before] rev 0e9e189444, board pimoroni-pico-2-plus
-- basic VFS -- -- directories --
-- write-once enforcement -- -- defragmentation --
-- strict mapping semantics -- -- power loss during create (clean) --
-- XIP mapping -- -- power loss during create (torn) --
-- concurrent mappings -- -- power loss during unlink --
-- cross-task pin refcounting -- -- power loss during mkdir and rmdir --
-- pin release on task exit -- -- power loss during defrag --
swept 110 injection points, covering every operation of the whole pass
==== 90 passed, 0 failed ====
[identity ok after] rev 0e9e189444, board pimoroni-pico-2-plus
```
Same suite on `sim:xipfs`: `==== 90 passed, 0 failed ====`.
### `nxflatxip` on hardware
```
=== NXFLAT module executed in place from xipfs ===
staged 268 bytes to /mnt/xipfs/xipmod
extent: block 97 x1, size 268, flash addr 0x10161000
running two concurrent instances...
[while running] pin count on the shared text = 2
instance seed 1: text 0x10161070, stack 0x20006980, sum 2080 -- data
private and intact
instance seed 2: text 0x10161070, stack 0x20007588, sum 4160 -- data
private and intact
[after exit] pin count on the shared text = 2 (released when this task
exits)
=== done ===
```
### `nxflatxip defrag` on hardware
```
[1] writing 55 files...
[2] deleting every other file to fragment it...
[3] requesting a 209-block (836 KB) contiguous file
result: FAILED -ENOSPC (free space is not contiguous)
[4] compacting...
elapsed : 1230 ms
extents relocated: 27
blocks reclaimed : 27
largest free run : 913408 bytes (223 blocks)
stop reason : 0 (done)
[5] retrying, sized to the reported largest run (223 blocks)
result: OK -- allocation now fits
[6] verifying every relocated file byte-for-byte
all survivors intact
[7] remounting to prove it is durable
all files intact after remount
=== defrag complete ===
```
### `nxflatxip bench` on hardware
```
XIP read benchmark (256 KB)
before any flash write : 30 ms
after a flash write : 20 ms
```
### `xipfs` command on hardware
```
nsh> xipfs -n
/mnt/xipfs: 250 blocks of 4096 bytes (1000 KB)
file start blocks bytes pin
bin/greet 0 1 6 0
bin/sub/deep 1 1 5 0
0 |##................................................|
'.' free '#' in use 'P' pinned by a live mapping
used 2, free 248, largest free run 248 blocks (992 KB)
1 free run, fragmentation 0%
nothing to gain: all free space is already contiguous
```
`tools/checkpatch.sh -c -u -m -g` passes on every commit in the branch.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]