Blame SOURCES/rsyslog-8.24.0-rhbz1696686-imjournal-fsync.patch

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