AltraMayor / AltraMayor/f3

macOS + exFAT: F3 produces false corruption due to fsync semantics and POSIX_FADV_DONTNEED

Aperta
#252 0 commenti 2 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
C
Stelle
3.4k
Fork
177
Merge medio
2g 15h
PR unite (30g)
2

Descrizione

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)

---

Image

## 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.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.