On this page

Filesystem Implementation

Coverage: ext4 (extent tree/jbd2/delayed allocation) → XFS (AG/B+tree/reflink) → Btrfs (COW/subvolume/snapshot/checksum) → bcachefs (6.7+) Kernel versions: 2.6 ~ 6.x

Overview

Linux supports various local filesystems, each with different design philosophies:

  • ext4: Stability-first, journal + delayed allocation, suitable for general-purpose scenarios
  • XFS: Large-scale parallel I/O, Allocation Group (AG) design, suitable for large files and high concurrency
  • Btrfs: COW + checksum + snapshot, suitable for NAS and scenarios requiring data integrity guarantees
  • bcachefs: Next-generation COW filesystem (6.7+), copygc + multiple devices + compression

ext4: A Stable General-Purpose Solution

Extent Tree

// ext4 uses an extent tree to replace indirect blocks (indirect/double-indirect/triple-indirect in ext2/3)
// An extent describes: "file offset X ~ X+LEN maps to disk block Y ~ Y+LEN"

struct ext4_extent {
    __le32  ee_block;       // Logical block number (file offset)
    __le16  ee_len;         // Number of blocks covered by this extent
    __le16  ee_start_hi;    // High 16 bits of the physical block number
    __le32  ee_start_lo;    // Low 32 bits of the physical block number (48-bit block number)
};

// The extent tree is a B-tree (located within the inode or in separate blocks)
// ext4_inode->i_data[60] = 4 ext4_extents + 1 header
//   → The first 4 extents exist directly in the inode (no additional block read needed!)
//   → If more than 4 → splits into B-tree nodes

// Why is this better than indirect blocks?
//   Indirect blocks: N blocks → O(N) lookup (one pointer per block)
//   Extents:         N blocks → O(1) extent coverage (contiguous blocks use one record)
//   Fragmented files: extent tree may have multiple nodes → still O(log N)

jbd2: Journal

// Write operation path in ext4:
//   1. Write data to disk (data)
//   2. Write metadata changes to journal (metadata)
//   3. Mark journal commit as complete
//   4. Checkpoint: write metadata from journal back to its actual location
//
// On mount:
//   Check journal → replay transactions that are committed but not yet checkpointed
//   → Restores consistency (fsck is rarely needed)

// data=ordered (default):
//   Write data first → then write to journal → data is not visible before metadata
//   → File data remains intact after a crash (metadata may be incomplete but won't point to garbage)

// data=writeback:
//   Data can be written out of order → faster, but may see stale data after a crash

Delayed Allocation

ext4 delayed allocation:
  Write operation → accumulate in page cache first → do not immediately allocate disk blocks
  → On writeback (after accumulating for a few seconds) → allocate large contiguous extents
  → Reduces fragmentation, improves sequential write performance

Costs:
  1. write() returning success does not mean disk space is allocated → ENOSPC is delayed until writeback
  2. More data loss on crash (dirty pages in page cache, disk blocks not yet allocated)

fallocate can be used to pre-allocate space, avoiding delayed ENOSPC

XFS: Large-Scale Parallelism

Allocation Groups (AG)

XFS divides the filesystem into multiple AGs (Allocation Groups)
Each AG independently manages its own inodes and free space B+tree
  → Multiple threads can allocate in parallel → avoids global locks
  → Outperforms ext4 in high-concurrency scenarios (e.g., multi-threaded databases)

AGs: [AG 0] [AG 1] [AG 2] ... [AG N]
  Each AG: has its own superblock copy, inode B+tree, free space B+tree

B+tree Metadata

// Almost all metadata in XFS is organized as B+trees:
//   inode B+tree:    inode number → inode data
//   free space B+tree: offset → free extent
//   extent B+tree:     file offset → disk extent (per-inode)
//
// Generic B+tree implementation: fs/xfs/libxfs/xfs_btree.c
XFS 5.x+ supports reflink (shared data blocks, COW):
  cp --reflink=always a b
    → a and b share the same data extent
    → When either is modified → COW → copy the modified block → they become independent

Difference from Btrfs:
  XFS reflink is extent-level COW — does not copy the entire file
  Btrfs is file-level COW — each snapshot/subvolume writes independently

Btrfs: COW and Data Integrity

COW Architecture

Btrfs COW:
  All writes go to new locations → old data is never overwritten
  1. Allocate a new extent from free space
  2. Write new data
  3. Update metadata B-tree to point to the new extent
  4. Old extent becomes free

  Crash safety:
    Because it is COW → old data always remains in place
    → No journal needed (snapshots and reflink are natively supported)
    → Transaction commit = write new root to superblock

  Costs:
    Fragmentation (frequent COW → logically contiguous data is physically scattered)
    Write amplification (small modifications → copy entire extent)

Core Features

Snapshots:
  btrfs subvolume snapshot . snapshots/$(date +%Y%m%d)
    → O(1) creation, no data copying
    → COW guarantee: modifying the original subvolume does not affect the snapshot

Subvolumes:
  Independent namespaces, can be mounted separately
  Similar to ZFS dataset concept

Checksums:
  Every data block and metadata block has a checksum (crc32c)
  Checked automatically on read → detects bit rot / silent corruption
  Works with RAID1 profile: detects corruption → auto-repairs from mirror

Compression:
  mount -o compress=zstd → compresses per extent (zlib/lzo/zstd)

B-tree Forest

Btrfs metadata organization:
  Multiple B-trees (sharing B-tree code):
    Root tree    → points to roots of other trees
    FS tree      → inodes for files/directories (one per subvolume)
    Extent tree  → extent allocation status
    Chunk tree   → mapping of chunk groups to physical blocks
    Device tree  → device information
    Csum tree    → extent checksums

bcachefs: Next-Generation (6.7+)

Design goals: "Btrfs features + ext4/XFS performance + ZFS data reliability"
Author: Kent Overstreet (original author of bcache)

Core features:
  - Primarily COW, optional journal
  - Multi-device: different disks can take on different roles
    (SSD for foreground/cache, HDD for cold storage)
  - Built-in compression (zstd/lz4/gzip) + checksums
  - Built-in encryption (per-extent)
  - Subvolumes / snapshots
  - Stable disk format (merged into mainline 6.7)

Difference from Btrfs:
  bcachefs was designed with multi-device tiering in mind from the start
  Btrfs RAID is configured at the filesystem level, bcachefs is more flexible

Filesystem Selection

Featureext4XFSBtrfsbcachefs
Max Volume1EB8EB16EB8EB
Max File16TB8EB16EB8EB
COWNoreflink onlyYesYes
SnapshotsNoNoYesYes
Built-in CompressionNoNoYesYes
Built-in RAIDNoNoYesYes
Checksumsjournal onlyjournal onlymetadata+datametadata+data
Suitable ScenariosGeneral purposeLarge files/databasesNASExperimental/multi-device

References and Further Reading

  • Kernel Documentation: Documentation/filesystems/ext4/, Documentation/filesystems/xfs/, Documentation/filesystems/btrfs.rst
  • LWN:
    • "bcachefs merged" (lwn.net/Articles/947587/)
    • "Btrfs: design and implementation" series
  • Source Code: fs/ext4/, fs/xfs/, fs/btrfs/, fs/bcachefs/

Keywords: ext4, extent tree, jbd2, delayed allocation, XFS, allocation group, B+tree, Btrfs, COW, checksum, bcachefs