APFS is prone to data loss on hard power-off in ways that HFS+ is not

Originator:mark
Number:rdar://32926460 Date Originated:2017-06-22
Status:Duplicate/32747641 (Closed) Resolved:2017-07-25
Product:macOS + SDK Product Version:10.13db2 17A291j
Classification:Crash/Hang/Data Loss Reproducible:Always
 
Radar 32925139 rendered my system unable to shut down or reboot by normal means, so I was forced to hold the power button to perform a hard power-off. Upon rebooting, I discovered that recently created files on an APFS volume were missing or filled with zeroes instead of their expected content.

Notably, files that are recently created linker output exist and have the correct size, but are filled with zeroes. (They’re actually sparse files, the zeroes occupy no space on disk.)

When a system is forced to power off due to losing power, due to holding the power button (as in radar 32925139 when the system needed to be rebooted to restore networking but refused to shut down), or likely due to a kernel panic, this form of data loss occurs. In my case, this occurred during a build of Google Chrome, and files for all recent linker output existed on disk but contained no data. The timestamps were current so the build system didn’t believe these files to need rebuilding, but because they contained no data, it was not possible to use them. In effect, this had corrupted the entire build.

This is especially troubling because the linker (ld64) takes care to write its output file “safely” to avoid data loss. Rather than writing its output (in the example below, the mmap_write executable) in place, it writes it to a temporary file and then moves the temporary file to its desired output location. This is the best practice for avoiding data loss and partial or corrupt files, but APFS+ defeats this best practice and allows the new file to exist without any of its proper contents after a power event.

Although any filesystem may be susceptible to this sort of problem on hard power-off, I experience it with APFS every single time. For comparison, despite my best efforts to reproduce on HFS+, I was not able to on that filesystem, even on the same OS version that I experience trouble with APFS.

Steps to Reproduce:
The attached test program, mmap_write.c, will use the mmap() interface to write a file.

Here, the current directory is on an APFS volume, and /Volumes/HFSPlus is an HFS+ volume.

litterbox@litterbox zsh% clang -g mmap_write.c -o mmap_write
litterbox@litterbox zsh% ./mmap_write file && ./mmap_write /Volumes/HFSPlus/file

Immediately after that command completes, hold down the power button for several seconds. The system will power down. Reboot it and look at mmap_write, file, and /Volumes/HFSPlus/file.

Expected Results:
I expect mmap_write to exist and have its correct contents, a Mach-O executable compiled from mmap_write.c. file should exist on both the APFS and HFS+ volumes, and each should be filled with 1MB of 0xff bytes.

Observed Results:
mmap_write on the APFS volume exists and has the correct size, but is a wholly sparse file. After rebooting:

litterbox@litterbox zsh% ./mmap_write    
zsh: exec format error: ./mmap_write
litterbox@litterbox zsh% stat -f '%z %b' mmap_write
8980 0

That “stat” shows that the file is 8,980 bytes long, but occupies zero blocks on disk—it’s wholly sparse, and all 8,980 bytes will read as zero.

However, on the HFS+ volume, the file exists at its full length and contains 0xff bytes.

Version:
10.13db2 17A291j with Xcode 9b2 9M137d
I also experienced this on 10.13db1 17A264c with Xcode 9b1 9M136h.

Comments

2017-07-25 19:41 UTC from Apple

The original report on your issue has been closed recently. Please note that you will not be able to directly view the original report in order to keep its information confidential.

If you have further questions about this issue, please update your report using the Apple Bug Reporter http://bugreport.apple.com.

2017-06-28 07:31 UTC from Apple

Engineering has determined that your bug report is a duplicate of another issue and will be closed.

The open or closed status of the original report your bug was duplicated to appears in a text box within the bug detail section of the bug reporter user interface. For security and privacy reasons, we don't provide access to the original bug yours was duped to.

If you have any questions or concerns, please update your report directly at this link: https://bugreport.apple.com/.

mmap_write.c

https://pastebin.com/buMVzjpF


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!