aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2018-04-20 11:21:08 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2018-04-23 14:25:28 +0200
commitcf0277928fa8d955d75f661021845789194dfff7 (patch)
treeda392672c936ad9f6a91c2d77c4377a22ac127d4
parent8b262eb2d80bfa27ae8501078ce47bc1407e9c55 (diff)
downloadbitcoin-cf0277928fa8d955d75f661021845789194dfff7.tar.xz
Add logging and error handling for file syncing
Add logging and error handling inside, and outside of FileCommit. Functions such as fsync, fdatasync will return error in case of hardware I/O errors, and ignoring this means it can silently continue through data corruption. (c.f. https://lwn.net/SubscriberLink/752063/12b232ab5039efbe/)
-rw-r--r--src/addrdb.cpp3
-rw-r--r--src/util.cpp28
-rw-r--r--src/util.h2
-rw-r--r--src/validation.cpp16
4 files changed, 36 insertions, 13 deletions
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index e4620e63c6..59305ff187 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -49,7 +49,8 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
// Serialize
if (!SerializeDB(fileout, data)) return false;
- FileCommit(fileout.Get());
+ if (!FileCommit(fileout.Get()))
+ return error("%s: Failed to flush file %s", __func__, pathTmp.string());
fileout.fclose();
// replace existing file, if any, with new file
diff --git a/src/util.cpp b/src/util.cpp
index 4fb027b731..9a3067259f 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -788,21 +788,37 @@ bool TryCreateDirectories(const fs::path& p)
return false;
}
-void FileCommit(FILE *file)
+bool FileCommit(FILE *file)
{
- fflush(file); // harmless if redundantly called
+ if (fflush(file) != 0) { // harmless if redundantly called
+ LogPrintf("%s: fflush failed: %d\n", __func__, errno);
+ return false;
+ }
#ifdef WIN32
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
- FlushFileBuffers(hFile);
+ if (FlushFileBuffers(hFile) == 0) {
+ LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
+ return false;
+ }
#else
#if defined(__linux__) || defined(__NetBSD__)
- fdatasync(fileno(file));
+ if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
+ LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
+ return false;
+ }
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
- fcntl(fileno(file), F_FULLFSYNC, 0);
+ if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
+ LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
+ return false;
+ }
#else
- fsync(fileno(file));
+ if (fsync(fileno(file)) != 0 && errno != EINVAL) {
+ LogPrintf("%s: fsync failed: %d\n", __func__, errno);
+ return false;
+ }
#endif
#endif
+ return true;
}
bool TruncateFile(FILE *file, unsigned int length) {
diff --git a/src/util.h b/src/util.h
index 6e742f8b91..ce94f396af 100644
--- a/src/util.h
+++ b/src/util.h
@@ -71,7 +71,7 @@ bool error(const char* fmt, const Args&... args)
}
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
-void FileCommit(FILE *file);
+bool FileCommit(FILE *file);
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
diff --git a/src/validation.cpp b/src/validation.cpp
index daa33d3f5a..158bdcc63f 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1615,22 +1615,27 @@ void static FlushBlockFile(bool fFinalize = false)
LOCK(cs_LastBlockFile);
CDiskBlockPos posOld(nLastBlockFile, 0);
+ bool status = true;
FILE *fileOld = OpenBlockFile(posOld);
if (fileOld) {
if (fFinalize)
- TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
- FileCommit(fileOld);
+ status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
+ status &= FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
if (fFinalize)
- TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
- FileCommit(fileOld);
+ status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
+ status &= FileCommit(fileOld);
fclose(fileOld);
}
+
+ if (!status) {
+ AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
+ }
}
static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
@@ -4760,7 +4765,8 @@ bool DumpMempool(void)
}
file << mapDeltas;
- FileCommit(file.Get());
+ if (!FileCommit(file.Get()))
+ throw std::runtime_error("FileCommit failed");
file.fclose();
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
int64_t last = GetTimeMicros();