Skip to content

Commit 5bc916f

Browse files
committed
1 parent 93971b0 commit 5bc916f

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

Sources/Containerization/Mount.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,15 @@ extension Mount {
163163

164164
extension VZDiskImageStorageDeviceAttachment {
165165
static func mountToVZAttachment(mount: Mount, options: [String]) throws -> VZDiskImageStorageDeviceAttachment {
166-
var cachingMode: VZDiskImageCachingMode = .automatic
166+
// Bug #57 (HIGH): VZDiskImageCachingMode.automatic can bypass the macOS page cache for
167+
// reads while writes go through it. On a sparse APFS file this causes a specific
168+
// incoherence: Linux writes to a block, the write lands in the page cache, but a
169+
// subsequent read bypasses the cache and hits APFS directly — which returns zeros from
170+
// the sparse hole, because the APFS extent was never allocated on disk yet. Data just
171+
// written becomes invisible immediately. Use .cached so reads always go through the
172+
// macOS page cache and see the most recent writes.
173+
// See: https://github.com/apple/container/pull/1041, https://github.com/utmapp/UTM/pull/5919
174+
var cachingMode: VZDiskImageCachingMode = .cached
167175
var synchronizationMode: VZDiskImageSynchronizationMode = .fsync
168176

169177
for option in options {
@@ -178,8 +186,9 @@ extension VZDiskImageStorageDeviceAttachment {
178186
switch key {
179187
case "vzDiskImageCachingMode":
180188
switch value {
181-
case "automatic":
182-
cachingMode = .automatic
189+
// Bug #57 (HIGH): "automatic" was removed; VZDiskImageCachingMode.automatic
190+
// causes filesystem corruption with sparse VirtIO block devices on Apple
191+
// Virtualization Framework and must not be used.
183192
case "cached":
184193
cachingMode = .cached
185194
case "uncached":

Sources/ContainerizationEXT4/BUGFIXES.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,16 +1074,32 @@ ext4-bugs X
10741074

10751075
---
10761076

1077+
## 57. HIGH: `VZDiskImageCachingMode.automatic` causes read-after-write incoherence on sparse VirtIO block devices, corrupting ext4 directories
1078+
1079+
**File:** `Sources/Containerization/Mount.swift:166`
1080+
**Bug:** The default `VZDiskImageCachingMode` for VirtIO block device attachments was `.automatic`. With sparse backing files and the Apple Virtualization Framework VirtIO block backend, `.automatic` can internally bypass the macOS page cache for reads while still buffering writes in it, creating a read-after-write hazard: a guest read of a just-written sparse block may return the old zeros from APFS storage instead of the newly written data. This corrupts ext4 directory blocks whose content has been written by the guest but whose backing storage is still a sparse hole:
1081+
```
1082+
EXT4-fs error (device vdb): ext4_readdir:262: inode #33249: block 131675: comm dnf:
1083+
path /usr/lib/python3.9/site-packages/dnf/module: bad entry in directory:
1084+
rec_len is smaller than minimal - offset=0, inode=0, rec_len=0, size=4096 fake=0
1085+
```
1086+
Confirmed by `lseek(SEEK_DATA/SEEK_HOLE)` analysis: the directory data block at APFS offset 131675 is a sparse hole (never materialized to APFS storage) while Python reads via the page cache return valid data. The bug manifests under memory pressure after long-running builds when page cache dirty pages are selectively evicted to APFS. The issue is a known defect in the Apple Virtualization Framework VirtIO block backend, independently confirmed and fixed in UTM (utmapp/UTM#5919) and apple/container (#1041).
1087+
**Fix:** Change the default to `.cached`, which ensures reads always go through the macOS page cache and see the most recently written data. Remove `.automatic` from the set of allowed override values to prevent callers from re-enabling the broken mode.
1088+
1089+
ext4-bugs X
1090+
1091+
---
1092+
10771093
## Summary
10781094

10791095
| Severity | Count |
10801096
|----------|-------|
10811097
| CRITICAL | 7 |
1082-
| HIGH | 17 |
1098+
| HIGH | 18 |
10831099
| MEDIUM | 16 |
10841100
| LOW | 12 |
10851101
| FALSE POSITIVE | 4 |
1086-
| **Total** | **56** |
1102+
| **Total** | **57** |
10871103

10881104
### Merged (4 pairs → 4 entries)
10891105
| Merged | Into | Reason |

0 commit comments

Comments
 (0)