From 628d791b26062945fad4afa5985f6b84f46f16d4 Mon Sep 17 00:00:00 2001 From: Jiri Vymazal Date: Tue, 23 Jul 2019 11:28:31 +0200 Subject: [PATCH] Add "fsync" option for imjournal The new option makes possible to force physical write of stateFile to persistent storage, ensuring we do not lose/duplicate messages in case of hard crash or power loss. --- plugins/imjournal/imjournal.c | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletitions(-) diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c index 5739bf408c..6c8829243a 100644 --- a/plugins/imjournal/imjournal.c +++ b/plugins/imjournal/imjournal.c @@ -24,6 +24,7 @@ #include "config.h" #include "rsyslog.h" #include +#include #include #include #include @@ -81,6 +82,7 @@ static struct configSettings_s { int bUseJnlPID; char *dfltTag; int bWorkAroundJournalBug; + int bFsync; } cs; static rsRetVal facilityHdlr(uchar **pp, void *pVal); @@ -99,7 +99,8 @@ static struct cnfparamdescr modpdescr[] = { { "defaultfacility", eCmdHdlrString, 0 }, { "usepidfromsystem", eCmdHdlrBinary, 0 }, { "defaulttag", eCmdHdlrGetWord, 0 }, - { "workaroundjournalbug", eCmdHdlrBinary, 0 } + { "workaroundjournalbug", eCmdHdlrBinary, 0 }, + { "fsync", eCmdHdlrBinary, 0 } }; static struct cnfparamblk modpblk = { CNFPARAMBLK_VERSION, @@ -437,7 +437,7 @@ persistJournalState(int trySave) persistJournalState(int trySave) { DEFiRet; - FILE *sf; /* state file */ + FILE *sf = NULL; /* state file */ char tmp_sf[MAXFNAME]; int ret = 0; @@ -468,13 +468,6 @@ persistJournalState(int trySave) ret = fputs(last_cursor, sf); if (ret < 0) { errmsg.LogError(errno, RS_RET_IO_ERROR, "imjournal: failed to save cursor to: '%s'", tmp_sf); - ret = fclose(sf); - ABORT_FINALIZE(RS_RET_IO_ERROR); - } - - ret = fclose(sf); - if (ret < 0) { - errmsg.LogError(errno, RS_RET_IO_ERROR, "imjournal: fclose() failed for path: '%s'", tmp_sf); ABORT_FINALIZE(RS_RET_IO_ERROR); } @@ -484,7 +477,30 @@ persistJournalState(int trySave) ABORT_FINALIZE(RS_RET_IO_ERROR); } + if (cs.bFsync) { + if (fsync(fileno(sf)) != 0) { + LogError(errno, RS_RET_IO_ERROR, "imjournal: fsync on '%s' failed", cs.stateFile); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + /* In order to guarantee physical write we need to force parent sync as well */ + DIR *wd; + if (!(wd = opendir((char *)glbl.GetWorkDir()))) { + LogError(errno, RS_RET_IO_ERROR, "imjournal: failed to open '%s' directory", glbl.GetWorkDir()); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + if (fsync(dirfd(wd)) != 0) { + LogError(errno, RS_RET_IO_ERROR, "imjournal: fsync on '%s' failed", glbl.GetWorkDir()); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + } + finalize_it: + if (sf != NULL) { + if (fclose(sf) == EOF) { + LogError(errno, RS_RET_IO_ERROR, "imjournal: fclose() failed for path: '%s'", tmp_sf); + iRet = RS_RET_IO_ERROR; + } + } RETiRet; } @@ -746,6 +747,8 @@ CODESTARTbeginCnfLoad cs.iDfltFacility = DFLT_FACILITY; cs.dfltTag = NULL; cs.bUseJnlPID = 0; + cs.bWorkAroundJournalBug = 0; + cs.bFsync = 0; ENDbeginCnfLoad @@ -943,6 +963,8 @@ CODESTARTsetModCnf cs.dfltTag = (char *)es_str2cstr(pvals[i].val.d.estr, NULL); } else if (!strcmp(modpblk.descr[i].name, "workaroundjournalbug")) { cs.bWorkAroundJournalBug = (int) pvals[i].val.d.n; + } else if (!strcmp(modpblk.descr[i].name, "fsync")) { + cs.bFsync = (int) pvals[i].val.d.n; } else { dbgprintf("imjournal: program error, non-handled " "param '%s' in beginCnfLoad\n", modpblk.descr[i].name);