Skip to content

Commit 4be426f

Browse files
laanwjfurszy
authored andcommitted
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/)
1 parent 8662fb3 commit 4be426f

File tree

4 files changed

+41
-18
lines changed

4 files changed

+41
-18
lines changed

src/addrdb.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
5151

5252
// Serialize
5353
if (!SerializeDB(fileout, data)) return false;
54-
FileCommit(fileout.Get());
54+
if (!FileCommit(fileout.Get()))
55+
return error("%s: Failed to flush file %s", __func__, pathTmp.string());
5556
fileout.fclose();
5657

5758
// replace existing file, if any, with new file

src/util.cpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -638,21 +638,37 @@ bool TryCreateDirectory(const fs::path& p)
638638
return false;
639639
}
640640

641-
void FileCommit(FILE* fileout)
641+
bool FileCommit(FILE* file)
642642
{
643-
fflush(fileout); // harmless if redundantly called
643+
if (fflush(file) != 0) { // harmless if redundantly called
644+
LogPrintf("%s: fflush failed: %d\n", __func__, errno);
645+
return false;
646+
}
644647
#ifdef WIN32
645-
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout));
646-
FlushFileBuffers(hFile);
647-
#else
648-
#if defined(__linux__) || defined(__NetBSD__)
649-
fdatasync(fileno(fileout));
650-
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
651-
fcntl(fileno(fileout), F_FULLFSYNC, 0);
648+
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
649+
if (FlushFileBuffers(hFile) == 0) {
650+
LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
651+
return false;
652+
}
652653
#else
653-
fsync(fileno(fileout));
654-
#endif
654+
#if defined(__linux__) || defined(__NetBSD__)
655+
if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
656+
LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
657+
return false;
658+
}
659+
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
660+
if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
661+
LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
662+
return false;
663+
}
664+
#else
665+
if (fsync(fileno(file)) != 0 && errno != EINVAL) {
666+
LogPrintf("%s: fsync failed: %d\n", __func__, errno);
667+
return false;
668+
}
669+
#endif
655670
#endif
671+
return true;
656672
}
657673

658674
bool TruncateFile(FILE* file, unsigned int length)

src/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ bool error(const char* fmt, const Args&... args)
8080
}
8181

8282
void PrintExceptionContinue(const std::exception* pex, const char* pszThread);
83-
void FileCommit(FILE* fileout);
83+
bool FileCommit(FILE* file);
8484
bool TruncateFile(FILE* file, unsigned int length);
8585
int RaiseFileDescriptorLimit(int nMinFD);
8686
void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length);

src/validation.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,22 +1388,27 @@ void static FlushBlockFile(bool fFinalize = false)
13881388
LOCK(cs_LastBlockFile);
13891389

13901390
CDiskBlockPos posOld(nLastBlockFile, 0);
1391+
bool status = true;
13911392

13921393
FILE* fileOld = OpenBlockFile(posOld);
13931394
if (fileOld) {
13941395
if (fFinalize)
1395-
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
1396-
FileCommit(fileOld);
1396+
status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
1397+
status &= FileCommit(fileOld);
13971398
fclose(fileOld);
13981399
}
13991400

14001401
fileOld = OpenUndoFile(posOld);
14011402
if (fileOld) {
14021403
if (fFinalize)
1403-
TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
1404-
FileCommit(fileOld);
1404+
status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
1405+
status &= FileCommit(fileOld);
14051406
fclose(fileOld);
14061407
}
1408+
1409+
if (!status) {
1410+
AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
1411+
}
14071412
}
14081413

14091414
bool FindUndoPos(CValidationState& state, int nFile, CDiskBlockPos& pos, unsigned int nAddSize);
@@ -4269,7 +4274,8 @@ bool DumpMempool(const CTxMemPool& pool)
42694274
}
42704275

42714276
file << mapDeltas;
4272-
FileCommit(file.Get());
4277+
if (!FileCommit(file.Get()))
4278+
throw std::runtime_error("FileCommit failed");
42734279
file.fclose();
42744280
if (!RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat")) {
42754281
throw std::runtime_error("Rename failed");

0 commit comments

Comments
 (0)