beamfs is an EM-resilient Linux filesystem. Every data block is a capsule
of sixteen interleaved Reed-Solomon RS(255,239) codewords; every read
decodes it, and a read beamfs cannot vouch for fails with -EIO instead
of returning wrong bytes. It descends from FTRFS and targets mainline
Linux.
Warning: beamfs 0.1.26 (beamfs-v3), and main since, have known
defects that lose data, weaken security or crash the kernel; read the
0.1.26 entry below before using it.
The full record is in CHANGELOG.md; its latest entries follow.
- Comments rewritten to describe the code as it is: the scrubber writes a corrected block back, the block bitmap is on disk, a capsule survives a burst of 129 coded bytes (not 139) and its parity is not interleaved, RS-mode indirect parity reports damage without repairing it, readdir positions are byte offsets, the size limits are those of the code. References to documents outside the tree, the project's stage numbering, version history and validation claims nothing in the tree substantiates are removed. Only comments and white space change: with the comments stripped, every source file is the same token stream.
u8andu16rather thanuint8_tanduint16_t,!prather thanp == NULL, andle16_add_cpu, as checkpatch --strict asks; no change in behaviour.refcount_trather thanatomic_tfor the slices of a folio still under writeback, as coccicheck asks: a count that would go below zero warns instead of wrapping.- The scrubber takes its snapshot of a block in a function of its own,
where the allocation mutex is taken and released unconditionally, and
a brace block that ran to the end of
beamfs_scrub_one_inodeis gone; no change in behaviour. - A test that could never be true (an 8-bit name length compared with
255) becomes a build-time check,
max()replaces a spelled-out maximum, and two lines past 100 columns are reflowed; no change in behaviour. - Releases are numbered the way the kernel numbers its own, as the
README now sets out under Versions:
beamfs-v3is 3.0, and the next release is 3.1, in place of the 0.2.0 announced before.
- This changelog. The README carries its latest entries at the top, and the warning on the known defects of 0.1.26 is now one of them.
tests/xfstests/: tests in the xfstests format, which the Yocto layer installs astests/beamfs(./check beamfs/001runs the first). Each checks one of the known defects of 0.1.26: 001 a new block that zeroes the rest of its page, 002 the set-user-ID and set-group-ID bits a write keeps, 003 a link count past 65535, 004st_blocks, 005--data-csumon rewritten and truncated blocks, 006 symbolic links of every length.tests/known-failures: the tests that fail on a known defect of 0.1.26, each with its defect and its reproducer, as measured on 7.3-rc6. beamfs-xfstests reads it: a sweep is clean only when every failure it finds is listed there and every test listed still fails, so the line of a test goes with the fix of its defect.tests/expected-kernel-messages: the kernel messages a test of the suite provokes on purpose, each with its test, the text it contains and why: dm-error under the volume (generic/338, 441, 484), a loop device on a full volume and the count of the errors the block layer held back (generic/361), a mount without a type, which tries every block filesystem the kernel knows on a beamfs volume (generic/067), exec with an empty argv (generic/633). beamfs-xfstests 2.5.4 reads it: any other message at warn or above during a test fails that test.
- The module links on i386: 64-bit divisions go through
div_u64,div_u64_remandDIV_ROUND_UP_ULL(before,__udivdi3and__divdi3were left undefined). - With
CONFIG_BEAMFS_ORDERED_META=y, a newly allocated data block was written and waited on after its buffer had been released, in four places; the buffer is now released afterwards. Without that option nothing changes. - A mount that runs out of memory while setting up the scratch pool, the superblock RS staging or the writeback page pool no longer leaks the superblock buffer, its copy and the pending RS events.
- When the per-CPU scratch array cannot be allocated at module load, a case meant to be survivable, the codec setup no longer writes through a NULL per-CPU pointer; each scratch allocation is tested, and the CPUs left without one are reported once.
- The module load fails with
-ENOMEMwhen the Reed-Solomon codec cannot be set up, instead of registering a filesystem whose every encode and decode returns-EINVAL; a load that fails after the codec is set up releases it. - A write by a user without
CAP_FSETIDclears the set-user-ID and set-group-ID bits, asgeneric_file_write_iterdoes: the write path callskiocb_modified(tests/xfstests/002). - The link count stops at 65535, what the inode stores: past it
link(2),mkdir(2)andrename(2)fail withEMLINK, where the count used to be cut when the inode was written (tests/xfstests/003). - With
--data-csum, a block written back or cut by a truncate reads back: its descriptor is stamped before the block's parity is computed, where a capsule had it stamped after and the next read put back what the page held. Without a descriptor to keep, its sixteen bytes are zeroed instead of carrying kernel memory to the medium (tests/xfstests/005). - A symbolic link target is at most what a data block holds, 3808
bytes in a capsule, and a longer one is refused with
ENAMETOOLONG, where 3809 to 3824 bytes were cut to 3808. A long target carries its descriptor, so it passes its check with--data-csum(tests/xfstests/006). - A write that starts a block inside a page no longer zeroes the rest
of that page: a freshly allocated block is no longer reported to
iomap as
IOMAP_F_NEW, which made it zero the page outside the bytes written, data of the block before included (tests/xfstests/001). st_blockscounts the blocks a file, a directory or a symbolic link holds on the medium, data and indirect alike: taken from the tree on the firststat, under the inode's allocation mutex, which a directory now grows under as a file does, and kept up to date by the allocator, where the page cache was counted and a file read 0 after a mount (tests/xfstests/004).- A full volume no longer prints
beamfs/inline: volume full, first refusal at ...as a kernel warning:ENOSPCis the caller's answer, and the line, printed once per boot and per site, said nothing of the volumes after the first (generic/027, generic/269 and generic/476 underbeamfs-xfstests2.5.2 and later). - A
remount,romarks the volume clean, as an unmount does, and aremount,rwmarks it in use again: the next mount no longer reports a volume put down properly as not cleanly unmounted (generic/452). Aremount,rwis refused on a volume that has failed or that carries unknownro_compatfeatures, which the first mount keeps read-only. - fsck.beamfs 0.1.9 and mkfs.beamfs 0.1.6 build with every warning on
and treated as an error, whatever
CFLAGSthe caller passes: their Makefiles add the list withoverride, where it was the default value ofCFLAGS, and the Yocto recipe of fsck.beamfs, which passes its own, built the checker of the nodes without-Werror. The list gains-Wsign-conversion,-Wmissing-declarations,-Werror=formatand, where the compiler has it,-fanalyzer; the conversions they found are spelled out where C made them, with the same machine code, except an inode's byte offset in fsck.beamfs, now computed unsigned throughout to the same value.make testintools/fsck.beamfsbuilds the tests it runs, and the manual page names the checker and its version. tools/sync-layer.shmirrors the formatter's Makefile into the Yocto layer, asMakefile.mkfs, for the recipe to build with; renames the formatter's recipe whenMKFS_BEAMFS_VERSIONmoves, where it was renamed by hand; and mirrors the checker'stests/, which it left behind, so the layer kept a copy that went stale.
The version the v3 report measures (commit 1bf151d), released as
beamfs-v3: 3.0 in the numbering that follows it.
A code review on 2026-10-09 found these defects in 0.1.26 and in every earlier version. They were established by reading the code; each fix in 3.1 comes with a test that reproduces the defect. Until a release says otherwise, do not keep data you cannot afford to lose on beamfs, do not mount an image you did not create, and do not mount beamfs where untrusted users can write to it.
Data loss:
- Sparse files: when the first block under a 4 KiB page is a hole, a read returns zeros for the whole page, including the data of the next block, and a later partial write of that page stores those zeros.
- Writes that start a new block inside a page that is not in the page cache can zero the rest of that page, data of the neighbouring blocks included (to be confirmed against the kernel's iomap).
- With two beamfs volumes mounted, the per-CPU cache of decoded indirect-parity regions can serve one volume's region to the other.
st_blocksis always 0, so tools that trust it (tar --sparse) archive files as holes.mkfs.beamfs --data-csumon the default (interleaved) layout: every block rewritten by writeback or truncate, and every symlink target of 96 bytes or more, fails its check on the next read (-EIO). The v3 measurements did not use this option.
Security:
- A write does not clear the set-user-ID and set-group-ID bits.
- The link count is not bounded: 65536 hard links, which an unprivileged user can make, wrap it to zero on disk, and the inode is later freed while names still point to it.
- 16 bytes of uninitialised kernel memory are written into each data block on the default layout.
Kernel crashes:
- The superblock geometry is not validated: a crafted or corrupted image can crash the kernel at mount.
- A mount that beamfs refuses after reading the root inode (data protection scheme 5, unknown indirect-parity mode) crashes the kernel.
The measurements of the v3 report stand as measured: none of the tests that ran detected these defects.
The beamfs v3 technical report measures beamfs 0.1.26, commit 1bf151d,
on Linux 7.3-rc5, on x86-64 and aarch64:
- xfstests,
autogroup, 734 tests: all 122 that ran on x86-64 passed, and 122 of the 123 that ran on aarch64 (generic/476was stopped by its time budget). xfstests declined the others, most of them for features beamfs does not implement; they are counted apart, not as passes. - Single-bit upsets injected into read bios by emufi 0.8.1, on a four-node aarch64 cluster and on USB flash media: beamfs never returned wrong data. It returned the correct file in every exercised case but one, and in that one refused the read. In the same runs ext4 and ext3 returned silently corrupted data, and btrfs refused the read.
- The injector itself is audited: on this kernel emufi logs one of its two read hooks one bio before the block it flips, and the report reconstructs the hook of every flip.
The limits of these measurements are in section X of the report, the work toward v4 in section XI.
- Report: 10.5281/zenodo.23253350 (all versions: 10.5281/zenodo.19886191). The record also holds the workspace with the raw run records, the root images and kernels measured, their build records, and the source trees of the Yocto layer, the xfstests harness and the bench at the commits used.
- Sources of the report:
papers/2026-10-beamfs-v3/. - Tags:
beamfs-v3is the measured code plus the report;beamfs-v2is the publicmainbefore v3.
- beamfs v3, technical report: 10.5281/zenodo.23253350
- beamfs v2: 10.5281/zenodo.19886192
- EMUFI v1, the fault injector: 10.5281/zenodo.20041762
- RadFI v1, methodology: 10.5281/zenodo.19885777
- FTRFS v1, the predecessor: 10.5281/zenodo.19824442
- FTRFS RFC to linux-fsdevel, April 2026: lore.kernel.org
- ORCID: 0009-0002-0912-9487
The FTRFS name and original concept originate in:
Fuchs, C.M., Langer, M., Trinitis, C. (2015). FTRFS: A Fault-Tolerant Radiation-Robust Filesystem for Space Use. ARCS 2015, Lecture Notes in Computer Science, vol 9017. Springer. DOI: https://doi.org/10.1007/978-3-319-16086-3_8
FTRFS v1 (Desbrieres, 2026) is an independent open-source realisation of that design on contemporary Linux. beamfs is a new filesystem with its own on-disk format rather than a further FTRFS revision: the limits of FTRFS are conceptual (threat model, where correction sits, scale, kernel integration), as section II of the v3 report sets out. The soundness theorem of the first beamfs report was falsified by fault injection and withdrawn in v2.
*.c,*.h: kernel module sourcesKconfig,Makefile: kernel build gluetools/: userspace tools (mkfs.beamfs,fsck.beamfs) and helper scriptsDocumentation/: design notes, on-disk format, known limitations, roadmappapers/: LaTeX sources of the reportscontext/: working rules and notes of the project
beamfs is built into the kernel of a Yocto image by the layer
yocto-beamfs, which carries a copy of the module sources; for v3 every
source file of the module was checked to have the same hash in this
repository and in the layer. The v3 measurements used layer commit
9d43172, Linux 7.3-rc5 (72d3fcf8) and CONFIG_BEAMFS_FS=y on both
architectures. The layer is not public: its
source tree at 9d43172 is in the Zenodo record of the v3 report, with
the images built from it.
A build of the module alone against a kernel tree:
make KDIR=<path-to-kernel-build>
checks that it compiles; only the image build exercises the target kernel.
- beamfs-xfstests: the xfstests harness used for v3.
- beamfs-bench: the bench that ran the fault-injection campaign of v3.
yocto-beamfs(the Yocto layer, which also carries emufi 0.8.1) andbeamfs-overlay(Gentoo ebuilds) are not public; their source trees at the commits the v3 measurements used are in the Zenodo record.
- beamfs 0.1.26 measured on two architectures (v3 report)
- Code public on GitHub, reports on Zenodo
- v4, the items of section XI of the v3 report: indirect blocks with
a whole parity slot and a generation,
DATA_CSUMandDATA_SELFIDby default, parity interleaving, a fixed injector, a beam campaign - beamfs 3.1: the fixes of the known defects of 0.1.26 (see the changelog), each with its test
- beamfs RFC to linux-fsdevel
beamfs numbers its releases the way the kernel numbers its own
(Documentation/process/2.Process.rst), not by semantic versioning:
- A release is a signed tag on
main,beamfs-vX.Y, as mainline releases are tagsvX.Y. It carries everything merged since the previous one, new work, cleanups and fixes alike. Y goes up by one at each release. X goes up when it is deemed time to, as the kernel's does when its second number is deemed large enough, and says nothing about compatibility; the next is planned with the work of section XI of the v3 report.beamfs-v3is 3.0. beamfs-vX.Y.Zis a stable update of X.Y: fixes already onmainand nothing else, on a branch cut from thebeamfs-vX.Ytag, under the rules ofDocumentation/process/stable-kernel-rules.rst. There is none so far.- The number in the source changes only at a tag. The tagged commit
sets
MODULE_VERSIONto X.Y.Z, Z being 0 for a release; between two tags the source keeps the number of the last one, and a build is identified by its commit (git describe) and by the module'ssrcversion. - Compatibility is not carried by the number. The format of a volume
is carried by its feature flags (compat, ro_compat, incompat), as in
ext2 and ext4. Interfaces to userspace fall under the kernel's rule
of no regressions, as
Documentation/admin-guide/reporting-regressions.rststates it: once described inDocumentation/ABI, an interface can gain features but does not break, short of grave errors or security problems, and is removed only after going throughobsolete(Documentation/ABI/README). - The tools in
tools/keep their own numbers, which move with each change to them; a release names the versions it carries.
The module of beamfs-v3 declares 0.1.26, the last number of the
scheme used before this one.
See papers/2026-10-beamfs-v3/README.md.
GPL-2.0-only (kernel module + userspace tools), CC-BY-4.0 (papers).
See COPYING and paper headers.