macOS + exFAT: F3 produces false corruption due to fsync semantics and POSIX_FADV_DONTNEED
- Dominant language
- C
- Stars
- 3.4k
- Forks
- 177
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 2
Description
When running **F3 on macOS with exFAT-formatted devices**, the tool may report **systematic data corruption (typically exactly one cluster, e.g. 128 KB = 256 sectors)** even on brand-new, healthy storage.
After extensive investigation, this appears to be **a tool–OS–filesystem semantic mismatch**, not actual media corruption.
This issue does **not** reproduce on:
- APFS (macOS)
- Linux (ext4 / exFAT)
- Repeated runs on the same device (often disappears)
---
## Observed Symptoms
Typical output from `f3read` on macOS + exFAT:
- Exactly **one missing or corrupted cluster**
- Often **128 KB (256 sectors)**
- Reported as _corrupted_ or _overwritten_
- More visible on **HDDs or slower devices**
Example:
`Corrupted: 128.00 KB (256 sectors)`
exfat fs default cluster = 128KiB (256 sectors)
---
## Root Cause Analysis
```c
static int bdev_write_blocks(struct device *dev, const char *buf,
uint64_t first_pos, uint64_t last_pos)
{
struct block_device *bdev = dev_bdev(dev);
const int block_order = dev_get_block_order(dev);
size_t length = (last_pos - first_pos + 1) << block_order;
off_t offset = first_pos << block_order;
off_t off_ret = lseek(bdev->fd, offset, SEEK_SET);
int rc;
if (off_ret < 0)
return - errno;
assert(off_ret == offset);
rc = write_all(bdev->fd, buf, length);
if (rc)
return rc;
rc = fsync(bdev->fd); // <----- Not ready sync in macOS with exfat
if (rc)
return rc;
return posix_fadvise(bdev->fd, 0, 0, POSIX_FADV_DONTNEED); // <----- Drop page cache but not ready sync data to storage, data lose...
}
```
### Key point
> **On macOS, `fsync()` does NOT guarantee physical media persistence.**
This is a documented semantic difference from Linux.
### What F3 currently does (simplified)
`write(...) fsync(fd) posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)`
### What happens on macOS + exFAT
1. `write()` populates the page cache
2. `fsync()` flushes _known dirty pages_, but:
- does **not** guarantee all delayed clusters are committed
3. The **last cluster** (commonly one exFAT cluster = 128 KB) may still be pending
4. `POSIX_FADV_DONTNEED` aggressively discards page cache
5. On subsequent `read()`:
- data is reloaded from disk
- but the last cluster may contain:
- old data
- zeroes
- uninitialized content
👉 Result: **exactly one missing cluster**, consistently aligned to exFAT cluster size.
This is **not a block alignment issue**, **not an ioctl issue**, and **not a hardware failure**.
---
## Why APFS Does Not Show This Problem
APFS uses:
- Copy-on-write
- Transactional block allocation + data + metadata updates
- `fsync()` commits the whole transaction
Therefore, F3’s assumption:
> _“fsync means data is safely persistent”_
**happens to hold on APFS**, but **does not hold on exFAT**.
---
## Why This Is Not an exFAT “Bug”
exFAT:
- Has no journaling
- Has weak ordering guarantees
- Relies on cooperative cache behavior
macOS’s exFAT driver prioritizes performance and allows delayed allocation.
The behavior is **legal** under POSIX and macOS semantics.
---
## Why This Is Dangerous
- Users may falsely conclude:
- “My new SD card is defective”
- “The device has bad sectors”
- Especially harmful for:
- camera media
- large-capacity cards
- HDD-based storage
In reality, **the data may never have been written incorrectly at all**.
---
## Recommended Fixes
### Option 1 (Best): Use macOS-specific full sync
On macOS, replace `fsync()` with:
`fcntl(fd, F_FULLFSYNC)`
This guarantees data reaches physical media.
### Option 2: Remove `POSIX_FADV_DONTNEED` on macOS + exFAT
Avoid dropping page cache immediately after `fsync()` on macOS.
### Option 3: Document the limitation clearly
At minimum, warn users:
> **F3 results on macOS + exFAT may be unreliable unless F_FULLFSYNC is used.**
---
## Summary
- This is **not hardware corruption**
- This is **not block misalignment**
- This is **a filesystem + OS semantic mismatch**
- F3’s assumptions are valid on Linux and APFS
- They are **not valid on macOS + exFAT**
I’m reporting this to prevent false negatives and unnecessary device returns.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.