Split View: bcachefs가 이레이저 코딩의 experimental 딱지를 뗀 이야기 — 그리고 그게 무슨 뜻인지
bcachefs가 이레이저 코딩의 experimental 딱지를 뗀 이야기 — 그리고 그게 무슨 뜻인지
- 들어가며 — 드라마는 끝났고, 질문은 "그래서 지금 상태가 뭔가"
- 사실관계부터 — 커널에서 빠진 과정
- DKMS 전환, 그리고 뒤집힌 상하 관계
- 2026년의 진짜 뉴스 — 이레이저 코딩이 딱지를 뗐다
- 널리 퍼진 한 문장이 틀린 세 가지 이유
- bcachefs의 이레이저 코딩은 실제로 어떻게 동작하나
- "딱지를 뗐다"에 딸려 온 각주들
- 그래서 지금 이걸 어떻게 대해야 하나
- 마치며
- 참고 자료
들어가며 — 드라마는 끝났고, 질문은 "그래서 지금 상태가 뭔가"
bcachefs 이야기는 지난 2년간 대부분 사람 이야기였습니다. 누가 무슨 말을 했고, 어느 풀 리퀘스트가 -rc 몇에서 거부됐고, 메일링 리스트에서 무슨 일이 있었는지. 그 이야기는 이미 충분히 소비됐고, 여기서 반복할 생각은 없습니다.
대신 엔지니어에게 실제로 쓸모 있는 질문을 하겠습니다. 2026년 7월 현재, bcachefs는 기술적으로 어떤 상태인가? 그리고 그 상태를 알려면 트윗이나 뉴스 헤드라인이 아니라 무엇을 봐야 하는가?
결론부터 말하면, 2026년의 가장 구체적인 변화는 이레이저 코딩이 experimental 딱지를 뗀 것입니다. 그리고 이 사실을 요약한 문장 하나가 인터넷에 도는데, 날짜도 버전도 대상도 틀렸습니다. 그 문장이 왜 틀렸는지 추적하는 과정이 이 글의 절반입니다 — 왜냐하면 그 과정이 "딱지를 뗐다"는 선언을 어떻게 읽어야 하는지를 그대로 보여 주기 때문입니다.
사실관계부터 — 커널에서 빠진 과정
먼저 확인 가능한 사실만 정리합니다. 커널 git에서 직접 확인한 것들입니다.
2025년 8월 28일. 리누스 토발즈가 MAINTAINERS 파일 한 줄을 고칩니다. 커밋 ebf2bfec412a, 추가 1줄 삭제 1줄. 커밋 메시지는 두 문장이 전부입니다 — "MAINTAINERS: mark bcachefs externally maintained / As per many long discussion threads, public and private." LWN은 다음 날 이를 Bcachefs goes to "externally maintained"로 다뤘고, 당시엔 코드가 커널에 남은 채 업스트림 패치만 안 받는다는 뜻으로 읽혔습니다.
2025년 9월 29일. 리누스가 코드 자체를 지웁니다. 커밋 f2c61db29f277b9c80de92102fc532cc247495cd, 284개 파일, 추가 0줄 삭제 117,483줄. 커밋 메시지 전문은 이렇습니다.
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.
즉 제거의 명분은 감정이 아니라 버전 혼동입니다 — "이제 DKMS 모듈이 있으니, 커널 안의 사본은 낡은 코드가 된다. 버전 혼동을 피하려고 지운다." LWN의 Bcachefs removed from the mainline kernel(Jonathan Corbet, 2025년 9월 30일)이 이 커밋을 다뤘습니다.
검증은 간단합니다. 커널 태그 v6.17의 fs/bcachefs/에는 260개 항목이 있고, v6.18에는 그 디렉터리가 없습니다(404). 이 글을 쓰는 시점의 메인라인은 v7.2-rc3이고, 그 사이 어떤 릴리스에도 다시 들어오지 않았습니다.
여기서 순서가 중요합니다. bcachefs-tools 저장소에 DKMS 지원이 들어온 커밋(00ad9b1ed126, "add dkms support")은 2025년 9월 10일입니다. 제거 커밋보다 19일 앞섭니다. 리누스가 "It's now a DKMS module"이라고 쓴 건 예언이 아니라 관찰이었습니다 — 대체 배포 경로가 이미 존재했기 때문에 지울 수 있었던 것입니다.
DKMS 전환, 그리고 뒤집힌 상하 관계
프로젝트 자신의 설명이 가장 간결합니다. bcachefs.org 첫 화면에 이렇게 적혀 있습니다.
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.
"(Like ZFS!)"라는 괄호가 이 상황의 성격을 정확히 요약합니다. 라이선스 문제로 영원히 트리 밖에 있는 ZFS와 달리 bcachefs는 GPL이지만, 배포 형태만 놓고 보면 이제 같은 자리에 섰습니다.
6.16이라는 하한은 벤더 웹페이지의 주장이 아니라 코드에서 확인됩니다. dkms/dkms.conf.in에 이렇게 박혀 있습니다.
# kernels older than 6.16 are currently not supported
BUILD_EXCLUSIVE_KERNEL_MIN="6.16"
상한은 없습니다. 대신 릴리스 노트가 최신 커널을 따라갑니다 — v1.37.0은 "Linux 7.0 support", v1.38.7은 "Builds against Linux 7.2"라고 적었습니다. 커널 7.2는 아직 rc 단계인데도 그렇습니다. 트리 밖 모듈이 감수해야 하는 비용이 정확히 이것입니다: 커널 내부 API가 흔들릴 때마다 따라가야 하고, 그 일이 이제 릴리스 노트의 고정 항목이 됐습니다.
그리고 상하 관계가 뒤집혔습니다. bcachefs-tools 저장소의 doc/vendored-kernel-files.md 첫 문단이 이렇게 말합니다.
bcachefs source itself lives in
fs/and is developed in this repository directly — kernel-sidefs/bcachefs/is downstream of us now.
파일시스템 소스가 이제 tools 저장소 안의 fs/ 디렉터리에 살고, 커널 쪽은 다운스트림입니다. README에 따르면 scripts/install-to-kernel.sh가 fs/를 커널 트리의 fs/bcachefs/로 복사해 CONFIG_BCACHEFS_FS로 빌드할 수 있게 해 줍니다. 방향이 완전히 반대가 된 셈입니다.
2026년의 진짜 뉴스 — 이레이저 코딩이 딱지를 뗐다
여기부터가 본론입니다.
bcachefs의 이레이저 코딩(EC)은 2023년 11월부터 CONFIG_BCACHEFS_ERASURE_CODING이라는 별도 Kconfig 옵션 뒤에 숨어 있었습니다. 커밋 제목이 그대로입니다 — "bcachefs: Put erasure coding behind an EXPERIMENTAL kconfig option"(6a673880f92b). 파일시스템 전체가 실험적이던 시절에도, EC는 그보다 한 단계 더 실험적인 물건이었습니다.
그게 2026년에 바뀌었습니다. 순서는 이렇습니다.
2026년 2월 2일. 커밋 f42ccc690dd7 — "bcachefs: kill CONFIG_BCACHEFS_ERASURE_CODING". Kconfig 게이트가 사라집니다. 오늘 master의 fs/Kconfig를 받아서 grep 해 보면 "ERASURE"는 0건입니다.
2026년 3월 15일, v1.37.0. 릴리스 노트 하이라이트 첫 줄이 선언합니다.
- Erasure coding is no longer experimental; all the core functionality is
complete.
같은 릴리스에 새 온디스크 메타데이터 버전 bcachefs_metadata_version_erasure_coding이 들어갔고, EC 섹션은 이렇게 설명합니다 — "Erasure coding is now hooked up to reconcile: degraded stripes are now automatically repaired, like other degraded data, and can be reshaped as needed." 즉 손상된 스트라이프가 다른 손상 데이터와 똑같이 백그라운드에서 자동 복구되는 경로가 붙었다는 뜻입니다. 티어링 설정이나 크기가 섞인 장치 구성도 동작해야 한다고 적었습니다.
이게 뉴스입니다. 그리고 이 뉴스의 날짜는 2026년 3월 15일입니다. 이 날짜를 기억해 두십시오.
널리 퍼진 한 문장이 틀린 세 가지 이유
이 주제를 검색하면 이런 요지의 문장을 만나게 됩니다 — "2026년 6월 17일, bcachefs-tools v1.38.6이 experimental 딱지를 떼고 출시됐다." 그럴듯하고, 날짜도 버전도 구체적이고, 완전히 틀렸습니다. 세 겹으로 틀렸습니다.
첫째, 버전이 틀렸습니다. 문제의 커밋은 8fc60dd30a8c, 제목은 "ec is not experimental"입니다. 작성 시각은 2026-06-18T01:58:15Z입니다. 그런데 v1.38.6 태그는 2026-06-17T19:03:36Z에 찍혔습니다. 커밋이 태그보다 약 7시간 늦습니다. git으로 확인하면 명확합니다 — v1.38.6은 이 커밋을 포함하지 않고, 처음 포함한 릴리스는 v1.38.7(2026년 7월 3일)입니다. v1.38.6 릴리스 노트는 "Feature and performance release on top of v1.38.5. No on-disk format changes."로 시작하고, experimental이라는 단어는 한 번도 나오지 않습니다.
둘째, 규모가 틀렸습니다. 이 커밋은 파일 하나(fs/opts.h)의 문자열 한 줄을 고칩니다. 전부입니다.
- NULL, "Enable erasure coding (DO NOT USE YET)") \
+ NULL, "Enable erasure coding (RAID5/6, but no write hole)")\
커밋 메시지 본문은 딱 네 단어입니다 — "hasn't been for awhile." 켄트 오버스트리트 본인이 "이거 experimental 아닌 지 좀 됐다"고 말하고 있는 겁니다. 실제 선언은 석 달 전 v1.37.0에서 이미 났고, 6월의 이 커밋은 그때부터 방치돼 있던 옵션 설명 문자열을 뒤늦게 따라 고친 잡일입니다. 매뉴얼 페이지(bcachefs.8)는 더 오래 방치돼 있었습니다 — 거기 "DO NOT USE YET"이 지워진 건 6월 30일 커밋 c2b1c10fdd35("docs: clarify erasure coding replica limit")에 와서였습니다. 같은 커밋이 fs/opts.h의 문구도 다시 한 번 손봐서, 12일간 존재했던 "RAID5/6, but no write hole"은 지금의 "Enable erasure coding (RAID5/6; data replicas are capped at 3)"로 바뀌었습니다.
셋째, 대상이 틀렸습니다. 그리고 이게 제일 중요합니다. 딱지를 뗀 건 이레이저 코딩이지 파일시스템이 아닙니다. 오늘 master의 fs/Kconfig 첫머리는 이렇습니다.
config BCACHEFS_FS
tristate "bcachefs filesystem support (EXPERIMENTAL)"
depends on BLOCK
(EXPERIMENTAL). 2026년 7월 16일 현재, bcachefs는 자기 Kconfig에서 스스로를 실험적이라고 부르고 있습니다. 이 줄은 최근에 손대지도 않았습니다 — fs/Kconfig의 마지막 변경은 2026년 5월 21일이고, 쿼터 기본값을 바꾸는 무관한 커밋이었습니다.
정리하면 이렇게 됩니다. "한 서브시스템이 실험 딱지를 뗐다"가 "파일시스템이 실험 딱지를 뗐다"로, "3월 릴리스"가 "6월 릴리스"로, "포함되지 않은 버전"이 "포함된 버전"으로 각각 한 칸씩 밀린 겁니다. 개별 왜곡은 작지만, 합치면 의미가 반대편에 가 있습니다.
bcachefs의 이레이저 코딩은 실제로 어떻게 동작하나
딱지 이야기는 그만하고, 딱지가 붙어 있던 물건이 뭔지 봅시다. 프로젝트의 Principles of Operation(doc/bcachefs-principles-of-operation.tex)과 EC 구현 소스(fs/data/ec/create.c)의 문서 주석이 1차 소스입니다.
기본 골격. bcachefs는 Reed-Solomon 이레이저 코딩을 씁니다 — 대부분의 RAID5/6 구현과 같은 알고리즘입니다. erasure_code는 inode 단위 옵션이라, set-file-option으로 특정 디렉터리에만 켤 수 있습니다. 파일시스템 전체를 갈아엎지 않아도 된다는 뜻입니다. 중복도는 data_replicas 옵션에서 가져옵니다.
data_replicas=1— EC 비활성화data_replicas=2— 패리티 블록 1개(RAID-5 스타일)data_replicas=3— 패리티 블록 2개(RAID-6 스타일)
패리티는 최대 2개 블록으로 제한됩니다. 이게 옵션 설명에 적힌 "data replicas are capped at 3"의 정체입니다 — 임의의 숫자가 아니라 Reed-Solomon 패리티 개수 상한에서 나온 값입니다. 그리고 메타데이터의 이레이저 코딩은 지원하지 않습니다.
write hole을 어떻게 피하는가. 여기가 설계의 핵심입니다. PoO의 설명을 옮기면, 전통적 RAID에서 write hole은 심각한 문제입니다 — 스트라이프 안의 작은 쓰기가 P/Q 패리티 블록 갱신을 요구하는데 이 쓰기들을 원자적으로 할 수 없어서, 크래시가 패리티를 불일치 상태로 남기면 같은 스트라이프에 있는 무관한 데이터의 재구성 읽기까지 망가집니다. ZFS는 모든 쓰기를 새 스트라이프로 만들어 이를 피하지만, PoO는 그 대가로 단편화가 성능을 해친다고 지적합니다 — 조각난 데이터의 읽기는 가장 느린 조각의 지연에 묶이고, 그래서 중앙값 지연이 꼬리 지연 쪽으로 끌려갑니다.
bcachefs의 답은 COW를 이용해 둘 다 피하는 것입니다. PoO의 표현 그대로 — 제자리 갱신이 근본 원인이니 아예 하지 않고, extent 단위 스트라이프는 ZFS와 같은 단편화를 부르니 버킷 전체를 인코딩합니다.
구현 주석이 설명하는 쓰기 경로는 이렇습니다.
1. 포그라운드 쓰기는 평범하게 복제된다 (data_replicas=2면 사본 2개)
2. reconcile 스레드가 EC 후보 버킷(복제 데이터가 든 버킷)을 추적
3. 후보가 충분히 쌓이면 백그라운드 EC 작업이:
- 데이터 버킷 한 묶음을 취하고 (예: 무관한 데이터가 든 버킷 5개)
- 패리티 버킷을 할당하고 (예: RAID-6 스타일이면 2개)
- 데이터 버킷들에 걸쳐 Reed-Solomon 패리티를 계산해 쓰고
- 원본 버킷을 가리키던 모든 extent를 갱신:
여분 복제 포인터를 버리고,
재구성 읽기가 필요하다는 플래그와 함께 패리티 포인터를 추가
주석의 결론 문장이 명료합니다 — "This approach avoids the write hole entirely: parity is computed once for immutable data, and the extent updates are atomic btree operations." 패리티는 이미 불변이 된 데이터에 대해 한 번만 계산되고, extent 갱신은 원자적 btree 연산입니다. 갱신할 패리티가 없으니 뚫릴 구멍도 없습니다.
대신 붙는 제약. 공짜가 아닙니다. 주석이 스트라이프 수명을 이렇게 설명합니다 — 버킷들이 한 스트라이프로 묶이고 나면, 스트라이프 안의 모든 데이터가 죽거나 옮겨지기 전까지는 그중 어느 버킷도 재사용할 수 없습니다. copygc가 이 제약을 알고 있어서, 스트라이프가 단편화되면 스트라이프 전체를 비워 냅니다 — 살아 있는 데이터를 새 버킷으로 다시 쓰고 옛 스트라이프를 회수하는 식입니다. 즉 write hole을 피한 값을 백그라운드 쓰기 증폭으로 치릅니다.
읽기 경로는 평범합니다. EC 포인터가 붙은 extent를 읽을 때 먼저 데이터 버킷을 직접 읽고, 실패하면(장치 오프라인, 체크섬 오류) 재구성 읽기로 넘어가 살아남은 데이터 버킷과 패리티 버킷을 모아 Reed-Solomon으로 복원합니다.
"딱지를 뗐다"에 딸려 온 각주들
이제 정직해질 부분입니다. v1.37.0의 EC 섹션은 "no longer experimental"만 적고 끝나지 않았습니다. 바로 다음 항목이 이렇습니다.
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.
번역하면 — 게이트는 없앴지만 중요한 항목 하나가 아직 남아 있다. 스트라이프 할당이 여러 장치에서 비슷한 LBA에 블록을 잡아야, 어레이를 리실버링할 때 탐색(seek)이 생기지 않는다. 이건 1.38에 들어갈 것이다.
그래서 1.38에 들어갔을까요?
아니요. v1.38.0(4월 19일)부터 v1.38.8(7월 3일)까지 릴리스 노트 어디에도 이 항목이 없습니다. 해당 작업으로 보이는 커밋은 6cf75ca7c70f — "ec: allocate stripe blocks near the stripe's centroid", 작성 시각 2026-07-04T17:45:18Z, fs/data/ec/create.c에 48줄 추가 6줄 삭제입니다. v1.38.8 태그(2026-07-03T19:15:42Z)보다 하루 늦습니다. git으로 확인하면 v1.38.8은 이 커밋을 포함하지 않습니다. 2026년 7월 16일 현재, 이 작업은 master에만 있고 어떤 릴리스에도 들어가지 않았습니다.
게다가 그 커밋조차 자기 입으로 미완이라고 말합니다. 마지막 문단이 이렇습니다 — "Outlier reallocation - fixing up early blocks when the centroid settles elsewhere - follows in the next patch." 중심점이 나중에 다른 곳으로 정착했을 때 초기 블록들을 고쳐 잡는 일은 다음 패치로 미뤄졌습니다.
이 문제가 왜 3월에 "1.38에 들어갈 것"이었다가 7월까지 밀렸는지도 커밋 메시지에 힌트가 있습니다. 순진한 접근 — 블록들의 원시 오프셋 평균을 목표로 삼는 방식 — 은 오히려 상황을 악화시켰다고 합니다. 커밋 메시지에 따르면 그 방식은 모든 블록을 같은 절대 버킷 번호로 수렴시켜 탐색 지역성을 전혀 못 주면서, 할당기의 비례 채움과 싸웁니다. 저자가 든 예시는 1G/2G/4G/8G 장치를 섞은 테스트인데, 1G 장치가 26% 찰 동안 8G 짝은 3%에 머물러서, 작은 장치의 여유 공간에 구멍을 뚫고 조기 ENOSPC 쪽으로 밀었다고 합니다. (저자 자체 측정이고, 특정 테스트 구성의 관찰이며, 채택된 설계가 아니라 기각된 대안의 실패를 설명하는 숫자입니다. 벤치마크로 인용할 수 있는 값이 아닙니다.) 그래서 채택된 건 원시 오프셋이 아니라 장치별 위치 비율의 평균을 중심점으로 삼는 방식입니다 — 스트라이프는 크기가 다른 장치들에 걸치고, 같은 오프셋도 장치마다 다른 위치이기 때문입니다.
정리하면, 3월에 "남은 항목 하나"라고 적힌 것은 알고 보니 설계상 함정이 있는 문제였고, 7월 중순 현재 부분적 해법이 master에 막 들어갔으며, 그 해법도 후속 패치를 예고하고 있습니다.
그래서 지금 이걸 어떻게 대해야 하나
여기까지의 사실을 실무 판단으로 옮기면 이렇습니다.
"no longer experimental"이 실제로 보증하는 것. 핵심 기능이 완성됐고, 별도 빌드 게이트 뒤에 숨어 있지 않고, 손상된 스트라이프가 자동 복구 경로에 연결됐고, 온디스크 포맷 버전이 부여됐다는 것. 이건 진짜 진전이고, 릴리스 노트의 주장이 코드에서 그대로 확인됩니다.
보증하지 않는 것. 프로젝트 자신이 명시한 미완 항목이 없다는 뜻은 아닙니다 — 리실버 시 탐색 지역성 작업은 아직 릴리스되지 않았습니다. 그리고 파일시스템 전체의 성숙도에 대한 진술은 더더욱 아닙니다. BCACHEFS_FS는 오늘도 (EXPERIMENTAL)입니다.
쓰지 말아야 할 때.
- 되찾을 수 없는 데이터를 담을 때. 파일시스템이 스스로를 실험적이라고 부르는 동안은, 백업이 있고 그 백업을 복구해 본 적이 있는 데이터만 올리는 게 맞습니다. 이건 bcachefs를 깎아내리는 말이 아니라 프로젝트 자신의 Kconfig를 그대로 읽은 것입니다.
- 리실버 시간이 SLO인 어레이. 하필 아직 릴리스되지 않은 작업이 정확히 그 지점을 겨냥합니다. 큰 회전 디스크 어레이에서 EC를 쓰고 장치 교체 시간이 중요하다면, 지금은 그 개선이 없는 버전을 쓰게 됩니다.
- 커널을 마음대로 못 고르는 환경. DKMS는 6.16 이상을 요구합니다. 엔터프라이즈 배포판의 고정된 구형 커널을 쓴다면 선택지가 아닙니다. 그리고 트리 밖 모듈이므로 커널을 올릴 때마다 재빌드가 걸리고, 시큐어 부트를 쓴다면 모듈 서명이 별도 관심사가 됩니다(v1.38.7에 서명 지원과 사전 빌드 모듈 배포가 들어갔습니다).
- 메타데이터까지 EC로 아끼려는 계산. 지원하지 않습니다. 용량 계산을 그렇게 세웠다면 다시 하셔야 합니다.
써 볼 만할 때. 위 조건을 다 읽고도 괜찮다면 — 백업된 데이터, 유연한 커널, 리실버 시간에 여유 — EC의 설계 자체는 진지하게 매력적입니다. 버킷 단위 백그라운드 인코딩으로 write hole 없이 RAID5/6급 공간 효율을 얻으면서 ZFS식 스트라이프 단편화를 피한다는 조합은, 성립한다면 실제로 새로운 지점입니다. 그리고 inode 단위 옵션이라 콜드 데이터 디렉터리에만 켜 보는 식의 점진적 도입이 가능합니다. 기존 파일시스템들과의 일반적 비교는 ext4·XFS·ZFS·btrfs 심층 비교 편에 정리해 두었습니다.
마치며
두 가지를 가져가면 좋겠습니다.
첫째, bcachefs의 2026년은 드라마가 아니라 엔지니어링입니다. 커널에서 117,483줄이 빠진 건 2025년 9월의 일이고, 그 뒤로 프로젝트는 DKMS로 배포되며 계속 릴리스를 내고 있습니다 — Changelog.mdwn에서 2026년 날짜가 붙은 릴리스 항목은 v1.35.0(1월 12일)부터 v1.38.8(7월 3일)까지 20개입니다. 커널 소스가 tools 저장소로 옮겨 가 커널 쪽이 다운스트림이 됐고, 릴리스 노트는 rc 단계 커널까지 따라갑니다. 이건 안정된 운영이지, 표류가 아닙니다.
둘째, "experimental을 뗐다"는 문장은 항상 세 가지를 되물어야 합니다 — 무엇이(파일시스템인가 서브시스템인가), 언제(어느 릴리스 노트가 선언했는가), 그리고 남은 각주가 무엇인가. 이 사례에서 세 질문의 답은 각각 "이레이저 코딩만", "2026년 3월 15일 v1.37.0", "리실버 탐색 지역성 — 아직 릴리스 안 됨"이었습니다. 인터넷에 도는 요약은 세 개 다 놓쳤습니다.
그리고 이걸 알아내는 데 특별한 접근 권한은 필요 없었습니다. 공개된 git 태그 날짜, 커밋 하나의 diff, Changelog.mdwn, fs/Kconfig 파일 하나면 충분했습니다. 요약을 인용하기 전에 태그 날짜를 한 번 확인하는 습관 — 이 글에서 건질 게 하나라면 그겁니다. 이 정직함은 프로젝트 자신이 먼저 보여 준 것이기도 합니다. "no longer experimental"과 "one significant item is still remaining"을 같은 릴리스 노트의 연속된 두 문단에 나란히 적어 둔 건 켄트 오버스트리트 본인이니까요. 각주를 지운 건 프로젝트가 아니라 그걸 옮긴 사람들이었습니다.
참고 자료
- Bcachefs removed from the mainline kernel — LWN.net (Jonathan Corbet, 2025-09-30)
- Bcachefs goes to "externally maintained" — LWN.net (Jonathan Corbet, 2025-08-29)
- 커널 커밋 f2c61db29f27 — "Remove bcachefs core code" (284 files, -117,483)
- 커널 커밋 ebf2bfec412a — "MAINTAINERS: mark bcachefs externally maintained"
- bcachefs.org — DKMS 배포 안내와 배포판별 패키지
- bcachefs-tools — 공식 개발 저장소 (소스, 문서, 릴리스)
- Changelog.mdwn — v1.37.0의 EC 선언과 남은 항목, v1.38.x 릴리스 노트
- 커밋 8fc60dd30a8c — "ec is not experimental" (fs/opts.h 한 줄)
- 커밋 f42ccc690dd7 — "bcachefs: kill CONFIG_BCACHEFS_ERASURE_CODING"
- 커밋 6cf75ca7c70f — "ec: allocate stripe blocks near the stripe's centroid" (미릴리스)
- fs/Kconfig — BCACHEFS_FS는 여전히 (EXPERIMENTAL)
- fs/data/ec/create.c — EC 설계 문서 주석(DOC_LATEX)과 구현
- ext4·XFS·ZFS·btrfs 심층 비교 (관련 글)
bcachefs Drops the Experimental Tag from Erasure Coding — and What It Actually Means
- Introduction — The Drama Is Over; the Question Now Is "What's the Status"
- The Facts First — How It Left the Kernel
- The DKMS Transition, and a Reversed Hierarchy
- The Real 2026 News — Erasure Coding Drops the Tag
- Three Ways a Widely Circulated Sentence Gets It Wrong
- How bcachefs's Erasure Coding Actually Works
- The Footnotes Attached to "Dropped the Tag"
- So How Should You Treat This, Right Now
- Closing
- References
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-sidefs/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 disableddata_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
- Bcachefs removed from the mainline kernel — LWN.net (Jonathan Corbet, 2025-09-30)
- Bcachefs goes to "externally maintained" — LWN.net (Jonathan Corbet, 2025-08-29)
- Kernel commit f2c61db29f27 — "Remove bcachefs core code" (284 files, -117,483)
- Kernel commit ebf2bfec412a — "MAINTAINERS: mark bcachefs externally maintained"
- bcachefs.org — DKMS distribution notes and per-distro packages
- bcachefs-tools — the official development repository (source, docs, releases)
- Changelog.mdwn — v1.37.0's EC declaration and remaining item, v1.38.x release notes
- Commit 8fc60dd30a8c — "ec is not experimental" (one line in fs/opts.h)
- Commit f42ccc690dd7 — "bcachefs: kill CONFIG_BCACHEFS_ERASURE_CODING"
- Commit 6cf75ca7c70f — "ec: allocate stripe blocks near the stripe's centroid" (unreleased)
- fs/Kconfig — BCACHEFS_FS is still (EXPERIMENTAL)
- fs/data/ec/create.c — EC design documentation comments (DOC_LATEX) and implementation
- ext4/XFS/ZFS/btrfs deep-dive comparison (related post)