Skip to content

필사 모드: bcachefs Drops the Experimental Tag from Erasure Coding — and What It Actually Means

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

Introduction — The Drama Is Over; the Question Now Is "What's the Status"

For the past two years, the bcachefs story has mostly been a story about people — who said what, which pull request got rejected at which -rc, what happened on the mailing list. That story has already been thoroughly consumed, and there's no need to repeat it here.

Instead, let's ask the question that's actually useful to an engineer. As of July 2026, what state is bcachefs technically in? And to find out, what should you actually look at — not tweets or news headlines?

The short answer: the single most concrete change of 2026 is that erasure coding dropped its experimental tag. And one sentence summarizing this fact is circulating online — it gets the date, the version, and the target all wrong. Tracing why that sentence is wrong makes up half of this post, because the process itself shows exactly how a "dropped the tag" declaration should be read.

The Facts First — How It Left the Kernel

Let's start with only what's verifiable — things confirmed directly from the kernel git history.

August 28, 2025. Linus Torvalds edits a single line in the MAINTAINERS file. Commit ebf2bfec412a, one line added, one line removed. The commit message is just two sentences — "MAINTAINERS: mark bcachefs externally maintained / As per many long discussion threads, public and private." LWN covered this the next day as Bcachefs goes to "externally maintained", and at the time it was read as meaning the code would stay in the kernel but simply stop receiving upstream patches.

September 29, 2025. Linus removes the code itself. Commit f2c61db29f277b9c80de92102fc532cc247495cd, 284 files, 0 lines added, 117,483 lines deleted. Here is the full commit message.

Remove bcachefs core code

bcachefs was marked 'externally maintained' in 6.17 but the code
remained to make the transition smoother.

It's now a DKMS module, making the in-kernel code stale, so remove
it to avoid any version confusion.

In other words, the justification for removal wasn't emotional — it was version confusion. "There's now a DKMS module, so the copy inside the kernel would just go stale. Remove it to avoid version confusion." LWN's Bcachefs removed from the mainline kernel (Jonathan Corbet, September 30, 2025) covered this commit.

Verification is simple. The kernel tag v6.17 has 260 entries under fs/bcachefs/, and v6.18 has no such directory at all (404). As of this writing, mainline is at v7.2-rc3, and the code has not returned in any release since.

The order here matters. The commit that brought DKMS support into the bcachefs-tools repository (00ad9b1ed126, "add dkms support") landed on September 10, 2025 — 19 days before the removal commit. When Linus wrote "It's now a DKMS module," that wasn't a prediction; it was an observation. The removal was only possible because an alternative distribution path already existed.

The DKMS Transition, and a Reversed Hierarchy

The project's own description puts it most concisely. The front page of bcachefs.org reads:

As of 6.18, bcachefs is no longer being distributed with the kernel, for reasons too complicated to go into here. (But it might have something to do with QA). So we're shipping as a DKMS module now. (Like ZFS!). The DKMS package supports Linux 6.16 and later.

That parenthetical "(Like ZFS!)" captures the situation exactly. Unlike ZFS, which stays out of the tree forever for licensing reasons, bcachefs is GPL — but purely in terms of how it's distributed, the two now stand in the same spot.

That 6.16 floor isn't just a vendor webpage's claim — it's confirmed in the code. dkms/dkms.conf.in has this baked in:

# kernels older than 6.16 are currently not supported
BUILD_EXCLUSIVE_KERNEL_MIN="6.16"

There's no ceiling. Instead, the release notes chase the latest kernel — v1.37.0 noted "Linux 7.0 support," and v1.38.7 noted "Builds against Linux 7.2," even though kernel 7.2 is still at the rc stage. This is exactly the cost an out-of-tree module has to bear: it has to keep pace every time internal kernel APIs shift, and that work has now become a fixture in the release notes.

And the hierarchy has flipped. The first paragraph of doc/vendored-kernel-files.md in the bcachefs-tools repository states:

bcachefs source itself lives in fs/ and is developed in this repository directly — kernel-side fs/bcachefs/ is downstream of us now.

The filesystem source now lives in the fs/ directory inside the tools repository, and the kernel side is downstream. According to the README, scripts/install-to-kernel.sh copies fs/ into the kernel tree's fs/bcachefs/ so it can be built via CONFIG_BCACHEFS_FS. The direction has completely reversed.

The Real 2026 News — Erasure Coding Drops the Tag

Here's where the main story begins.

bcachefs's erasure coding (EC) had been hidden behind a separate Kconfig option, CONFIG_BCACHEFS_ERASURE_CODING, since November 2023. The commit title says it plainly — "bcachefs: Put erasure coding behind an EXPERIMENTAL kconfig option" (6a673880f92b). Even back when the whole filesystem was experimental, EC was one notch more experimental still.

That changed in 2026. Here's the sequence.

February 2, 2026. Commit f42ccc690dd7 — "bcachefs: kill CONFIG_BCACHEFS_ERASURE_CODING." The Kconfig gate disappears. If you pull today's fs/Kconfig from master and grep it, "ERASURE" gets zero hits.

March 15, 2026, v1.37.0. The very first line of the release notes highlights declares it.

- Erasure coding is no longer experimental; all the core functionality is
  complete.

The same release shipped a new on-disk metadata version, bcachefs_metadata_version_erasure_coding, and the EC section explains: "Erasure coding is now hooked up to reconcile: degraded stripes are now automatically repaired, like other degraded data, and can be reshaped as needed." In other words, a path was added where a damaged stripe gets automatically repaired in the background, exactly like any other degraded data. It also states that tiering configurations and mixed-size device setups are expected to work.

This is the news. And the date of this news is March 15, 2026. Keep that date in mind.

Three Ways a Widely Circulated Sentence Gets It Wrong

Search for this topic and you'll run into a sentence along these lines — "On June 17, 2026, bcachefs-tools v1.38.6 shipped, dropping the experimental tag." It sounds plausible, it's specific about the date and the version, and it's completely wrong. Wrong in three separate ways.

First, the version is wrong. The commit in question is 8fc60dd30a8c, titled "ec is not experimental." It was authored at 2026-06-18T01:58:15Z. But the v1.38.6 tag was cut at 2026-06-17T19:03:36Z — the commit lags the tag by roughly 7 hours. Checking with git makes it clear: v1.38.6 does not contain this commit; the first release to include it is v1.38.7 (July 3, 2026). The v1.38.6 release notes open with "Feature and performance release on top of v1.38.5. No on-disk format changes," and the word "experimental" never appears in them.

Second, the scope is wrong. This commit touches a single line in a single file (fs/opts.h). That's the entirety of it.

-	  NULL,		"Enable erasure coding (DO NOT USE YET)")	\
+	  NULL,		"Enable erasure coding (RAID5/6, but no write hole)")\

The commit message body is exactly four words — "hasn't been for awhile." Kent Overstreet himself is saying "this hasn't been experimental for a while now." The actual declaration had already happened three months earlier, in v1.37.0 — this June commit is a housekeeping fix that belatedly caught up an option-description string that had been left stale since then. The man page (bcachefs.8) had been left stale even longer — the "DO NOT USE YET" there wasn't removed until commit c2b1c10fdd35 ("docs: clarify erasure coding replica limit") on June 30. That same commit also touched the wording in fs/opts.h once more, changing the "RAID5/6, but no write hole" phrasing — which had existed for 12 days — to the current "Enable erasure coding (RAID5/6; data replicas are capped at 3)."

Third, the target is wrong. And this is the part that matters most. What dropped the tag was erasure coding, not the filesystem. The top of today's fs/Kconfig on master reads:

config BCACHEFS_FS
	tristate "bcachefs filesystem support (EXPERIMENTAL)"
	depends on BLOCK

(EXPERIMENTAL). As of July 16, 2026, bcachefs still calls itself experimental in its own Kconfig. And this line hasn't even been touched recently — fs/Kconfig was last changed on May 21, 2026, in an unrelated commit that changed a quota default.

Put together: "one subsystem dropped the experimental tag" shifted one notch to "the filesystem dropped the experimental tag"; "the March release" shifted to "the June release"; and "a version that doesn't include it" shifted to "a version that does." Each individual distortion is small, but stacked together, the meaning ends up pointing the opposite direction.

How bcachefs's Erasure Coding Actually Works

Enough about the tag — let's look at what was actually behind it. The primary sources here are the project's Principles of Operation (doc/bcachefs-principles-of-operation.tex) and the documentation comments in the EC implementation source (fs/data/ec/create.c).

The basic shape. bcachefs uses Reed-Solomon erasure coding — the same algorithm behind most RAID5/6 implementations. erasure_code is an inode-level option, so it can be turned on for a specific directory via set-file-option. That means you don't have to convert the whole filesystem at once. Redundancy comes from the data_replicas option.

  • data_replicas=1 — EC disabled
  • data_replicas=2 — 1 parity block (RAID-5 style)
  • data_replicas=3 — 2 parity blocks (RAID-6 style)

Parity is capped at 2 blocks maximum. This is what "data replicas are capped at 3" in the option description actually refers to — not an arbitrary number, but a value derived from the Reed-Solomon parity-count ceiling. And metadata erasure coding is not supported.

How it avoids the write hole. This is the heart of the design. To paraphrase the PoO's explanation: in traditional RAID, the write hole is a serious problem — a small write inside a stripe requires updating the P/Q parity blocks, and because those writes can't be made atomic, a crash that leaves parity inconsistent can corrupt reconstructive reads of unrelated data sitting in the same stripe. ZFS avoids this by turning every write into a new stripe, but the PoO points out the cost: fragmentation hurts performance — reads of fragmented data get bound to the latency of the slowest fragment, which drags median latency toward tail latency.

bcachefs's answer is to use COW to dodge both problems at once. In the PoO's own words — since in-place updates are the root cause, don't do them at all; and since extent-level striping causes the same fragmentation as ZFS, encode whole buckets instead.

The write path described in the implementation comments looks like this.

1. Foreground writes are replicated normally (2 copies if data_replicas=2)
2. A reconcile thread tracks EC candidate buckets (buckets holding replicated data)
3. Once enough candidates accumulate, a background EC job:
   - takes a group of data buckets (e.g., 5 buckets holding unrelated data)
   - allocates parity buckets (e.g., 2, for RAID-6 style)
   - computes and writes Reed-Solomon parity across the data buckets
   - updates every extent that pointed at the original buckets:
       drops the spare replica pointer,
       adds a parity pointer flagged as requiring a reconstruct read

The comment's closing line puts it clearly — "This approach avoids the write hole entirely: parity is computed once for immutable data, and the extent updates are atomic btree operations." Parity is computed only once, on data that has already become immutable, and the extent update is an atomic btree operation. There's no parity left to update, so there's no hole left to open.

The tradeoff that comes with it. None of this is free. The comments describe the lifetime of a stripe like this — once buckets have been grouped into a stripe, none of those buckets can be reused until every piece of data in the stripe has either died or moved. copygc is aware of this constraint, so when a stripe fragments, it empties the entire stripe — rewriting the still-live data into new buckets and reclaiming the old stripe. In other words, you pay for avoiding the write hole with background write amplification.

The read path is unremarkable. Reading an extent with an EC pointer first tries the data bucket directly, and if that fails (device offline, checksum error), it falls back to a reconstruct read, gathering the surviving data buckets and parity buckets and rebuilding via Reed-Solomon.

The Footnotes Attached to "Dropped the Tag"

Time to be honest. The EC section of v1.37.0 didn't stop at "no longer experimental." The very next item reads:

Erasure coding is no longer hidden behind CONFIG_BCACHEFS_ERASURE_CODING, but one significant item is still remaining - stripe allocation needs to allocate blocks on different devices at similar LBAs, to avoid seeking when resilvering an array. This should land in 1.38.

In other words — the gate was removed, but one significant item is still remaining. Stripe allocation needs to place blocks at similar LBAs across different devices, so that resilvering an array doesn't trigger seeking. This, the note said, should land in 1.38.

So did it land in 1.38?

No. From v1.38.0 (April 19) through v1.38.8 (July 3), this item appears in none of the release notes. The commit that appears to be this work is 6cf75ca7c70f — "ec: allocate stripe blocks near the stripe's centroid," authored at 2026-07-04T17:45:18Z, 48 lines added and 6 removed in fs/data/ec/create.c. That's a day later than the v1.38.8 tag (2026-07-03T19:15:42Z). Checking with git confirms v1.38.8 does not include this commit. As of July 16, 2026, this work exists only on master and has not landed in any release.

What's more, the commit itself admits it's incomplete. Its final paragraph reads — "Outlier reallocation - fixing up early blocks when the centroid settles elsewhere - follows in the next patch." Fixing up the early blocks when the centroid later settles somewhere else has been deferred to the next patch.

The commit message also hints at why this issue slipped from "should land in 1.38" in March all the way to July. The naive approach — targeting the raw average of block offsets — reportedly made things worse. According to the commit message, that approach converged every block toward the same absolute bucket number, giving no seek locality at all, while fighting the allocator's proportional fill. The author's example is a test mixing 1G/2G/4G/8G devices: while the 1G device filled to 26%, its 8G counterpart sat at only 3%, punching a hole in the smaller device's free space and pushing it toward early ENOSPC. (This is a vendor self-measured figure, an observation from one specific test configuration, and a number describing the failure of a rejected alternative rather than the design that was actually adopted — not a figure you can cite as a benchmark.) What was adopted instead of raw offsets is a centroid based on the average of each device's positional ratio — because a stripe spans devices of different sizes, and the same offset sits at a different position on each device.

Put together: what was noted in March as "one item remaining" turned out to be a problem with a design trap in it, a partial fix has just landed on master as of mid-July, and even that fix is already flagging a follow-up patch.

So How Should You Treat This, Right Now

Translating everything above into a practical judgment:

What "no longer experimental" actually guarantees. Core functionality is complete, it's no longer hidden behind a separate build gate, damaged stripes are hooked into the automatic repair path, and an on-disk format version has been assigned. That's real progress, and the release notes' claim checks out against the code.

What it doesn't guarantee. It doesn't mean there are no remaining items the project itself has flagged — the resilver seek-locality work still hasn't shipped. And it's even less a statement about the maturity of the filesystem as a whole. BCACHEFS_FS is still (EXPERIMENTAL) today.

When not to use it.

  • When you're storing data you can't afford to lose. As long as the filesystem calls itself experimental, the right move is to only put data on it that's backed up — and that you've actually tested restoring from that backup. This isn't a knock against bcachefs; it's just reading the project's own Kconfig at face value.
  • Arrays where resilver time is an SLO. The work that hasn't shipped yet happens to target exactly that spot. If you're running EC on a large array of spinning disks and device-replacement time matters, you'll be running a version without that improvement.
  • Environments where you can't pick your kernel freely. DKMS requires 6.16 or later. If you're on an enterprise distro's pinned, older kernel, this isn't an option. And because it's an out-of-tree module, every kernel upgrade triggers a rebuild, and if you use Secure Boot, module signing becomes its own separate concern (v1.38.7 added signing support and prebuilt module distribution).
  • If you're counting on EC to save space on metadata too. It's not supported. If your capacity math assumed otherwise, you'll need to redo it.

When it's worth trying. If you've read all the conditions above and you're still fine — backed-up data, a flexible kernel, slack in resilver time — the design of EC itself is genuinely compelling. Getting RAID5/6-class space efficiency without a write hole, via bucket-level background encoding, while avoiding ZFS-style stripe fragmentation, is a genuinely new spot to stand in, if it holds up. And because it's an inode-level option, gradual adoption — turning it on only for cold-data directories, say — is possible. A general comparison against existing filesystems is covered separately in the ext4/XFS/ZFS/btrfs deep-dive comparison.

Closing

Two things are worth taking away.

First, bcachefs's 2026 is engineering, not drama. The 117,483 lines that came out of the kernel happened in September 2025, and since then the project has kept shipping releases distributed via DKMS — Changelog.mdwn lists 20 release entries dated in 2026, from v1.35.0 (January 12) through v1.38.8 (July 3). The kernel source moved into the tools repository, making the kernel side downstream, and the release notes now chase kernel versions all the way to the rc stage. This is stable operation, not drift.

Second, any sentence claiming "dropped the experimental tag" always deserves three follow-up questions — what (the filesystem, or a subsystem), when (which release notes made the declaration), and what footnotes remain. In this case, the answers to those three questions were, respectively, "erasure coding only," "March 15, 2026, v1.37.0," and "resilver seek locality — still not shipped." The summary circulating online missed all three.

And getting to the bottom of it didn't require any special access. Public git tag dates, the diff of a single commit, Changelog.mdwn, and one file — fs/Kconfig — were enough. If there's one habit worth taking from this post, it's checking a tag's date before you quote a summary. This honesty, for what it's worth, is something the project itself demonstrated first. It was Kent Overstreet himself who put "no longer experimental" and "one significant item is still remaining" side by side, in two consecutive paragraphs of the same release notes. It wasn't the project that dropped the footnote — it was the people who passed the summary along.

References

현재 단락 (1/96)

For the past two years, the bcachefs story has mostly been a story about people — who said what, whi...

작성 글자: 0원문 글자: 18,659작성 단락: 0/96