This PR attempts to close (or at least help) #26455 (and closed duplicates #26400 #26530).
Context
macOS’s fsync only flushes writes to the drive, but doesn’t ask the drive to immediately commit the data to permanent storage (ie - physically write it) (manpage). The data will eventually be physically written, but there are no guarantees when it will happen – it could be several seconds or more. For a stronger ‘immediate-write’ guarantee, they offer an F_FULLFSYNC option to fcntl (manpage) to accomplish that. This fsync-on-macOS behavior has caused historical problems in this project for macOS builds, so, since then, the F_FULLSYNC approach has been used for writing (see #3000).
However, certain external drives or filesystems do not support fcntl with F_FULLFSYNC option. (And some that do supposedly support the option do not actually do it.) These drives/filesystems will typically report errno ENOTSUP or ENOTTY, which is what was reported in the referenced issues. However, there is no reliable way to determine lack of support, so relying on specific error codes is insufficient.
This bug seems to only be affecting macOS 13 (Ventura) systems, but in theory, any macOS version could be affected.
What other projects have done
Other projects, including LevelDB, SQLite, and MariaDB have experienced similar issues, and have taken the strategy of falling back on the (less reliable) fsync when F_FULLFSYNC isn’t supported. (See helpful Twitter thread.) Some (SQLite, MariaDB, LevelDB) fall back to fsync on any error, and others only fall back on specific errors (BerkeleyDB 4.8 falls back only on ENOTSUP, which is why this PR may not fully fix #26455, as the wallet is getting the error ENOTTY.)
This PR
I propose to follow that general strategy and fall back on fsync if F_FULLFSYNC fails for any reason, while preserving both error codes for debugging.
(I think we should also print the error strings using SysErrorString rather than print the raw platform-dependent error codes, but I wanted to keep this PR as atomic as possible and save those changes (4 or 5 lines in addition to these) for another PR (which I’d be happy to submit – or modify this PR to include).)