util: detect and warn when using exFAT on macOS

exFAT is known to cause corruption on macOS. See #28552.

Therefore we should warn when using this fs format for either the blocks
or data directories on macOS.

Co-authored-by: l0rinc <pap.lorinc@gmail.com>
This commit is contained in:
willcl-ark
2024-12-05 22:06:13 +00:00
committed by will
parent 2bb06bcaf2
commit db3228042b
4 changed files with 61 additions and 0 deletions

View File

@@ -18,6 +18,8 @@
- [Installed Files](#installed-files)
- [Filesystem recommendations](#filesystem-recommendations)
## Data directory location
The data directory is the default location where the Bitcoin Core files are stored.
@@ -160,3 +162,8 @@ This table describes the files installed by Bitcoin Core across different platfo
- *Italicized* files are only installed in source builds if relevant CMake options are enabled. They are not included in binary releases.
- README and bitcoin.conf files are included in binary releases but not installed in source builds.
- On Windows, binaries have a `.exe` suffix (e.g., `bitcoin-cli.exe`).
## Filesystem recommendations
When choosing a filesystem for the data directory (`datadir`) or blocks directory (`blocksdir`) on **macOS**,the `exFAT` filesystem should be avoided.
There have been multiple reports of database corruption and data loss when using this filesystem with Bitcoin Core, see [Issue #31454](https://github.com/bitcoin/bitcoin/issues/31454) for more details.

View File

@@ -1866,6 +1866,26 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
}
#ifdef __APPLE__
auto check_and_warn_fs{[&](const fs::path& path, std::string_view desc) {
const auto path_desc{strprintf("%s (\"%s\")", desc, fs::PathToString(path))};
switch (GetFilesystemType(path)) {
case FSType::EXFAT:
InitWarning(strprintf(_("The %s path uses exFAT, which is known to have intermittent corruption problems on macOS. "
"Move this directory to a different filesystem to avoid data loss."), path_desc));
break;
case FSType::ERROR:
LogInfo("Failed to detect filesystem type for %s", path_desc);
break;
case FSType::OTHER:
break;
}
}};
check_and_warn_fs(args.GetDataDirNet(), "data directory");
check_and_warn_fs(args.GetBlocksDirPath(), "blocks directory");
#endif
#if HAVE_SYSTEM
const std::string block_notify = args.GetArg("-blocknotify", "");
if (!block_notify.empty()) {

View File

@@ -30,6 +30,11 @@
#include <shlobj.h>
#endif // WIN32
#ifdef __APPLE__
#include <sys/mount.h>
#include <sys/param.h>
#endif
/** Mutex to protect dir_locks. */
static GlobalMutex cs_dir_locks;
/** A map that contains all the currently held directory locks. After
@@ -298,3 +303,15 @@ std::optional<fs::perms> InterpretPermString(const std::string& s)
return std::nullopt;
}
}
#ifdef __APPLE__
FSType GetFilesystemType(const fs::path& path)
{
if (struct statfs fs_info; statfs(path.c_str(), &fs_info)) {
return FSType::ERROR;
} else if (std::string_view{fs_info.f_fstypename} == "exfat") {
return FSType::EXFAT;
}
return FSType::OTHER;
}
#endif

View File

@@ -14,6 +14,23 @@
#include <limits>
#include <optional>
#ifdef __APPLE__
enum class FSType {
EXFAT,
OTHER,
ERROR
};
/**
* Detect filesystem type for a given path.
* Currently identifies exFAT filesystems which cause issues on macOS.
*
* @param[in] path The directory path to check
* @return FSType enum indicating the filesystem type
*/
FSType GetFilesystemType(const fs::path& path);
#endif
/**
* Ensure file contents are fully committed to disk, using a platform-specific
* feature analogous to fsync().