Checkpoint (CHKP)
The Checkpoint is the atomic commit point of a ReFS volume. A volume keeps two alternating checkpoints; each is one metadata page — 4 consecutive clusters on 4K-cluster volumes (16 KiB page) or 1 cluster on 64K-cluster volumes (64 KiB page). The copy with the higher virtual clock is the current one, and the lower-clock copy is the previous consistent state (a rollback target until the next flush).
Field Layout
| Offset | Size | Field | Description |
|---|---|---|---|
| 0x00 | 80 | Page header | Common metadata page header (see Page Header) with signature "CHKP" |
| 0x50 | 4 | Version echo (u32) | Packed `minor«16 |
| 0x54 | 2 | Major version (u16) | Always 3 |
| 0x56 | 2 | Minor version (u16) | 4, 7, 9, 10, or 14 |
| 0x58 | 4 | Self-descriptor offset (u32) | In-page offset of the checkpoint’s own page reference — the descriptor whose first LCN slot is the checkpoint page itself. 0xD0 (v3.4–v3.10), 0xE0 (v3.14 and later), 0xE8 on some v3.14 images. Verified by reading the reference at this offset and comparing its slot 0 with the checkpoint’s own LCN: 95/95 corpus images, every version. Where the 0x88 region is populated it satisfies 0x88 == 0x58 + 14 × 0x5C (76/95) — the self-descriptor plus the 13 root references |
| 0x5C | 4 | Page reference size (u32) | 0x68 (v3.4), 0x30 (CRC64), 0x48 (SHA-256) |
| 0x60 | 8 | Virtual clock (u64) | Matches header at 0x10; the checkpoint sequence counter — increments on every committed checkpoint. Bootstrap selects the active checkpoint by the higher value. |
| 0x68 | 8 | Allocator clock (u64) | Always ≤ virtual clock. A separate counter advanced when the allocator’s persisted state changes; the gap = virtual − allocator is the count of checkpoints since the last allocation-table change. Forensic interpretation: a non-zero gap indicates recent checkpoints were metadata-only / in-place (no cluster allocation since the last allocator commit). The per-operation semantic is inferred from the offset relationship rather than verified at the operation level. |
| 0x70 | 8 | Oldest log record ref (u64) | Low 32 bits = log offset, high 32 bits = segment |
| 0x78 | 4 | CHKP flags (u32) | See CHKP Flags below |
| 0x7C | 12 | Reserved | Always zero |
| 0x88 | 4 | Data area end offset (u32) | 0x680 (v3.4), 0x380 (v3.14) on most checkpoints, but 0x0 on some v3.14-native images — the 0x88–0x8F region co-varies populated-vs-zeroed per checkpoint, so do not treat it as a fixed constant |
| 0x8C | 4 | Max root capacity (u32) | 0x20 (32) on most images but 0x0 on the same v3.14-native images as 0x88; the “MS_CHECKPOINT_MAX_ROOTS = 0x20” label holds only where the region is populated |
| 0x90 | 4 | Root count (u32) | Always 13 |
| 0x94 | var | Root pointer list | Direct (flag 0x0200 clear): 13 u32 in-page offsets start here, each pointing at one page reference elsewhere in the checkpoint — the references themselves do not start at 0x94. Indirect (0x0200 set): this is a u32 in-page offset to an array of 13 u32 offsets, each pointing at one root’s page reference, spaced 0x5C apart. It is not a pointer to a separate page — see the walk-through below |
Checkpoint selection and fallback
Each CHKP carries a self-checksum verified at mount — the algorithm is cluster-size-dependent (4-byte CRC32-C on 4K-cluster, 8-byte CRC64 on 64K-cluster, 32-byte SHA-256 on SHA-256 volumes), the same mechanism the Superblock uses. At mount, ChooseCheckpointRecord picks the copy with the highest virtual clock among the copies that pass their checksum. An invalid higher-clock copy is skipped, falling back automatically to the lower-clock valid copy; if both fail, the mount fails. Because each flush writes the other slot with clock+1, the lower-clock slot always holds the previous consistent state.
CHKP Flags (offset 0x78)
| Bit | Mask | Meaning | First Version |
|---|---|---|---|
| 1 | 0x0002 | Base flag (always set) | v3.4 |
| 7 | 0x0080 | Native format marker (not set on upgraded volumes) | v3.10 |
| 9 | 0x0200 | Indirect root list mode | v3.14 |
| 10 | 0x0400 | CRC64 metadata verification active | v3.14 |
| 4,5,8 | 0x0130 | Deduplication-related flags | v3.14 (dedup) |
| 13 | 0x2000 | Insider-only flag | Insider |
Composite Flag Values by Version
| Version | Flags (hex) | Flags (binary) | Key Bits |
|---|---|---|---|
| v3.4 | 0x0002 | 0000 0000 0010 | Base |
| v3.7 | 0x0002 | 0000 0000 0010 | Same |
| v3.9 | 0x0002 | 0000 0000 0010 | Same |
| v3.10 | 0x0082 | 0000 1000 0010 | +native format |
| v3.14 native | 0x0682 | 0110 1000 0010 | +indirect roots +CRC64 |
| v3.14 upgraded | 0x0602 | 0110 0000 0010 | +indirect +CRC64, missing native |
| v3.14 dedup/compress | 0x07b2 | 0111 1011 0010 | +dedup/compression feature bits (0x130) |
| Insider (native) | 0x2682 | 0010 0110 1000 0010 | native v3.14 + Insider flag |
| Insider (upgraded) | 0x2602 | 0010 0110 0000 0010 | upgraded (no 0x080) + Insider flag |
The 0x0080 bit cleanly separates native-formatted v3.10+ volumes (set) from upgraded-from-v3.4 volumes (clear) — an independent corroboration of the volume information driver-version-stamp upgrade signal.
Direct vs Indirect Root Access
The 13 root table pointers have two encodings, selected by flag bit 0x0200:
- Without 0x0200 (direct): CHKP+0x94 holds 13
u32in-page offsets, one per root. Each names a position within the same checkpoint page where that root’s page reference sits; the reference isdesc_lenbytes long (desc_lenfrom CHKP+0x5C). The offsets are at 0x94 — the page references are not. - With 0x0200 (indirect): CHKP+0x94 holds a u32 offset within the same checkpoint page to the root-list region (not a pointer to a separate page — the value is far smaller than one page and equals the embedded-data base offset)
Critical: A parser must read the flag bit before decoding the root list. Reading an indirect-mode checkpoint as direct (or vice versa) yields 13 wrong root addresses.
13 Root Table Pointers
| Index | Table | Table ID | Schema | Addressing | Failover Pair |
|---|---|---|---|---|---|
| 0 | Object ID Table | 0x02 | 0xe030 | Virtual | #5 |
| 1 | Medium Allocator | 0x21 | 0xe010 | Virtual | – |
| 2 | Container Allocator | 0x20 | 0xe010 | Virtual | – |
| 3 | Schema Table | 0x01 | 0xe060 | Virtual | #9 |
| 4 | Parent-Child Table | 0x03 | 0xe040 | Virtual | – |
| 5 | Object ID Table (dup) | 0x04 | 0xe030 | Virtual | – |
| 6 | Block Refcount | 0x05 | 0xe0b0 | Virtual | – |
| 7 | Container Table | 0x0B | 0xe0c0 | Real (physical) | #8 |
| 8 | Container Table (dup) | 0x0C | 0xe0c0 | Real (physical) | – |
| 9 | Schema Table (dup) | 0x06 | 0xe060 | Virtual | – |
| 10 | Container Index | 0x0E | 0xe100 | Virtual | – |
| 11 | Integrity State | 0x0F | 0xe080 | Virtual | – |
| 12 | Small Allocator | 0x22 | 0xe010 | Real (physical) | – |
Roots 7, 8, and 12 use real (physical) LCNs as a bootstrap exception; every other root uses virtual addressing (VLCN → PLCN via the Container Table).
Failover pairs: 0/5 (Object ID), 3/9 (Schema), 7/8 (Container). Block Refcount (#6) has no failover pair.
The Container-Table failover pair (roots 7 & 8) is the set {0x0B, 0x0C} at roots {7, 8} — the common ordering is root 7 = 0x0B / root 8 = 0x0C, but the two can appear swapped, so the invariant is the set, not a fixed index→Table-ID order.
Version Echo (offset 0x50)
| Scenario | Value |
|---|---|
| Native v3.14 | 0x000E0003 (minor=14, major=3) |
| Upgraded volumes | 0x00000000 |
| v3.4 through v3.9 | 0x00000000 |
The version echo distinguishes natively formatted v3.10+ volumes from upgraded ones.
Virtual Clock Typical Values
| Scenario | Approximate Value |
|---|---|
| Freshly formatted volume | ~20-30 |
| After ~1,000 file operations | ~50-100 |
| After v3.4 to v3.14 upgrade | +41 transactions |
Parsing Sequence
- Read 80-byte page header; verify signature is
"CHKP" - Read version at 0x54/0x56
- Read page reference size at 0x5C (determines stride for root list traversal)
- Read CHKP flags at 0x78
- Check bit 0x0200 to determine direct vs indirect root mode
- Parse the 13 root pointers at 0x94 — directly when flag 0x0200 is clear, otherwise follow the
u32there to the array of 13 in-page offsets and read one page reference at each (stride0x5C) - Optional cross-check: the reference at the offset in 0x58 is the checkpoint’s own self-descriptor — its first LCN slot equals the checkpoint’s LCN. A mismatch means the page is not the checkpoint you think it is
- For each root, use the appropriate addressing mode (virtual for most, physical for roots 7, 8, 12)
Cross-references
- Superblock (SUPB) – the SUPB stores pointers to the two CHKP locations
- Page References – the page reference size at CHKP+0x5C selects the format
- Object Table – root 0 (and failover root 5)
- Container Table – root 7 (and failover root 8)
- Container Index – root 10
- Allocators – roots 1, 2, 12
- Schema Table – root 3 (and failover root 9)
Evidence
The page header signature, the 13 root-table identities, the version fields, and the page-reference sizes are confirmed in the decompiled driver and the binary string literals; ValidateCheckpointRecord checks the flag bits at CHKP+0x78 and ChooseCheckpointRecord performs highest-clock selection. The flag composites, the version echo, the real-LCN bootstrap exception for roots 7/8/12, and the field offsets were re-measured directly on disk across the corpus. The 0x88/0x8C populated-vs-zeroed co-variation is confirmed. The CHKP flag decomposition is confirmed. The remaining field-level statements on this page are registered as — each with its own evidence tier and witness in the claim register.