Move journal sync function to util.cpp
Move it out of log_manager.cpp so other code will be able to call it.
The code itself wasn't changed, though a comment was modified, as it is
now a utility function it may no longer just be called when an error log
is created.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I33a20c1a68059fd50678464776e88168ce93d030
diff --git a/log_manager.cpp b/log_manager.cpp
index f2d1ef6..23e7bd6 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -8,8 +8,6 @@
#include "extensions.hpp"
#include "util.hpp"
-#include <poll.h>
-#include <sys/inotify.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-journal.h>
#include <unistd.h>
@@ -100,7 +98,7 @@
static constexpr auto transactionIdVarOffset = transactionIdVarSize + 1;
// Flush all the pending log messages into the journal
- journalSync();
+ util::journalSync();
sd_journal* j = nullptr;
int rc = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
@@ -609,150 +607,6 @@
}
}
-void Manager::journalSync()
-{
- bool syncRequested = false;
- auto fd = -1;
- auto rc = -1;
- auto wd = -1;
- auto bus = sdbusplus::bus::new_default();
-
- auto start =
- duration_cast<microseconds>(steady_clock::now().time_since_epoch())
- .count();
-
- // Each time an error log is committed, a request to sync the journal
- // must occur and block that error log commit until it completes. A 5sec
- // block is done to allow sufficient time for the journal to be synced.
- //
- // Number of loop iterations = 3 for the following reasons:
- // Iteration #1: Requests a journal sync by killing the journald service.
- // Iteration #2: Setup an inotify watch to monitor the synced file that
- // journald updates with the timestamp the last time the
- // journal was flushed.
- // Iteration #3: Poll to wait until inotify reports an event which blocks
- // the error log from being commited until the sync completes.
- constexpr auto maxRetry = 3;
- for (int i = 0; i < maxRetry; i++)
- {
- // Read timestamp from synced file
- constexpr auto syncedPath = "/run/systemd/journal/synced";
- std::ifstream syncedFile(syncedPath);
- if (syncedFile.fail())
- {
- // If the synced file doesn't exist, a sync request will create it.
- if (errno != ENOENT)
- {
- lg2::error(
- "Failed to open journal synced file {FILENAME}: {ERROR}",
- "FILENAME", syncedPath, "ERROR", strerror(errno));
- return;
- }
- }
- else
- {
- // Only read the synced file if it exists.
- // See if a sync happened by now
- std::string timestampStr;
- std::getline(syncedFile, timestampStr);
- auto timestamp = std::stoll(timestampStr);
- if (timestamp >= start)
- {
- break;
- }
- }
-
- // Let's ask for a sync, but only once
- if (!syncRequested)
- {
- syncRequested = true;
-
- constexpr auto JOURNAL_UNIT = "systemd-journald.service";
- auto signal = SIGRTMIN + 1;
-
- auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
- SYSTEMD_INTERFACE, "KillUnit");
- method.append(JOURNAL_UNIT, "main", signal);
- bus.call(method);
- if (method.is_method_error())
- {
- lg2::error("Failed to kill journal service");
- break;
- }
-
- continue;
- }
-
- // Let's install the inotify watch, if we didn't do that yet. This watch
- // monitors the syncedFile for when journald updates it with a newer
- // timestamp. This means the journal has been flushed.
- if (fd < 0)
- {
- fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
- if (fd < 0)
- {
- lg2::error("Failed to create inotify watch: {ERROR}", "ERROR",
- strerror(errno));
- return;
- }
-
- constexpr auto JOURNAL_RUN_PATH = "/run/systemd/journal";
- wd = inotify_add_watch(fd, JOURNAL_RUN_PATH,
- IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR);
- if (wd < 0)
- {
- lg2::error("Failed to watch journal directory: {PATH}: {ERROR}",
- "PATH", JOURNAL_RUN_PATH, "ERROR", strerror(errno));
- close(fd);
- return;
- }
- continue;
- }
-
- // Let's wait until inotify reports an event
- struct pollfd fds = {
- fd,
- POLLIN,
- 0,
- };
- constexpr auto pollTimeout = 5; // 5 seconds
- rc = poll(&fds, 1, pollTimeout * 1000);
- if (rc < 0)
- {
- lg2::error("Failed to add event: {ERROR}", "ERROR",
- strerror(errno));
- inotify_rm_watch(fd, wd);
- close(fd);
- return;
- }
- else if (rc == 0)
- {
- lg2::info("Poll timeout ({TIMEOUT}), no new journal synced data",
- "TIMEOUT", pollTimeout);
- break;
- }
-
- // Read from the specified file descriptor until there is no new data,
- // throwing away everything read since the timestamp will be read at the
- // beginning of the loop.
- constexpr auto maxBytes = 64;
- uint8_t buffer[maxBytes];
- while (read(fd, buffer, maxBytes) > 0)
- ;
- }
-
- if (fd != -1)
- {
- if (wd != -1)
- {
- inotify_rm_watch(fd, wd);
- }
- close(fd);
- }
-
- return;
-}
-
std::string Manager::readFWVersion()
{
auto version = util::getOSReleaseValue("VERSION_ID");
diff --git a/log_manager.hpp b/log_manager.hpp
index aa7d8f9..275530e 100644
--- a/log_manager.hpp
+++ b/log_manager.hpp
@@ -259,12 +259,6 @@
const std::vector<std::string>& additionalData,
AssociationList& objects) const;
- /** @brief Synchronize unwritten journal messages to disk.
- * @details This is the same implementation as the systemd command
- * "journalctl --sync".
- */
- void journalSync();
-
/** @brief Reads the BMC code level
*
* @return std::string - the version string
diff --git a/util.cpp b/util.cpp
index a89e754..da068e6 100644
--- a/util.cpp
+++ b/util.cpp
@@ -17,6 +17,17 @@
#include "util.hpp"
+#include <poll.h>
+#include <sys/inotify.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-journal.h>
+#include <unistd.h>
+
+#include <phosphor-logging/lg2.hpp>
+#include <sdbusplus/bus.hpp>
+
+#include <chrono>
+
namespace phosphor::logging::util
{
@@ -43,4 +54,147 @@
return std::nullopt;
}
+void journalSync()
+{
+ bool syncRequested = false;
+ auto fd = -1;
+ auto rc = -1;
+ auto wd = -1;
+ auto bus = sdbusplus::bus::new_default();
+
+ auto start = std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::steady_clock::now().time_since_epoch())
+ .count();
+
+ // Make a request to sync the journal with the SIGRTMIN+1 signal and
+ // block until it finishes, waiting at most 5 seconds.
+ //
+ // Number of loop iterations = 3 for the following reasons:
+ // Iteration #1: Requests a journal sync by killing the journald service.
+ // Iteration #2: Setup an inotify watch to monitor the synced file that
+ // journald updates with the timestamp the last time the
+ // journal was flushed.
+ // Iteration #3: Poll to wait until inotify reports an event which blocks
+ // the error log from being commited until the sync completes.
+ constexpr auto maxRetry = 3;
+ for (int i = 0; i < maxRetry; i++)
+ {
+ // Read timestamp from synced file
+ constexpr auto syncedPath = "/run/systemd/journal/synced";
+ std::ifstream syncedFile(syncedPath);
+ if (syncedFile.fail())
+ {
+ // If the synced file doesn't exist, a sync request will create it.
+ if (errno != ENOENT)
+ {
+ lg2::error(
+ "Failed to open journal synced file {FILENAME}: {ERROR}",
+ "FILENAME", syncedPath, "ERROR", strerror(errno));
+ return;
+ }
+ }
+ else
+ {
+ // Only read the synced file if it exists.
+ // See if a sync happened by now
+ std::string timestampStr;
+ std::getline(syncedFile, timestampStr);
+ auto timestamp = std::stoll(timestampStr);
+ if (timestamp >= start)
+ {
+ break;
+ }
+ }
+
+ // Let's ask for a sync, but only once
+ if (!syncRequested)
+ {
+ syncRequested = true;
+
+ constexpr auto JOURNAL_UNIT = "systemd-journald.service";
+ auto signal = SIGRTMIN + 1;
+
+ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "KillUnit");
+ method.append(JOURNAL_UNIT, "main", signal);
+ bus.call(method);
+ if (method.is_method_error())
+ {
+ lg2::error("Failed to kill journal service");
+ break;
+ }
+
+ continue;
+ }
+
+ // Let's install the inotify watch, if we didn't do that yet. This watch
+ // monitors the syncedFile for when journald updates it with a newer
+ // timestamp. This means the journal has been flushed.
+ if (fd < 0)
+ {
+ fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ if (fd < 0)
+ {
+ lg2::error("Failed to create inotify watch: {ERROR}", "ERROR",
+ strerror(errno));
+ return;
+ }
+
+ constexpr auto JOURNAL_RUN_PATH = "/run/systemd/journal";
+ wd = inotify_add_watch(fd, JOURNAL_RUN_PATH,
+ IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR);
+ if (wd < 0)
+ {
+ lg2::error("Failed to watch journal directory: {PATH}: {ERROR}",
+ "PATH", JOURNAL_RUN_PATH, "ERROR", strerror(errno));
+ close(fd);
+ return;
+ }
+ continue;
+ }
+
+ // Let's wait until inotify reports an event
+ struct pollfd fds = {
+ fd,
+ POLLIN,
+ 0,
+ };
+ constexpr auto pollTimeout = 5; // 5 seconds
+ rc = poll(&fds, 1, pollTimeout * 1000);
+ if (rc < 0)
+ {
+ lg2::error("Failed to add event: {ERROR}", "ERROR",
+ strerror(errno));
+ inotify_rm_watch(fd, wd);
+ close(fd);
+ return;
+ }
+ else if (rc == 0)
+ {
+ lg2::info("Poll timeout ({TIMEOUT}), no new journal synced data",
+ "TIMEOUT", pollTimeout);
+ break;
+ }
+
+ // Read from the specified file descriptor until there is no new data,
+ // throwing away everything read since the timestamp will be read at the
+ // beginning of the loop.
+ constexpr auto maxBytes = 64;
+ uint8_t buffer[maxBytes];
+ while (read(fd, buffer, maxBytes) > 0)
+ ;
+ }
+
+ if (fd != -1)
+ {
+ if (wd != -1)
+ {
+ inotify_rm_watch(fd, wd);
+ }
+ close(fd);
+ }
+
+ return;
+}
+
} // namespace phosphor::logging::util
diff --git a/util.hpp b/util.hpp
index c348916..0ac3878 100644
--- a/util.hpp
+++ b/util.hpp
@@ -16,4 +16,11 @@
*/
std::optional<std::string> getOSReleaseValue(const std::string& key);
+/**
+ * @brief Synchronize unwritten journal messages to disk.
+ * @details This is the same implementation as the systemd command
+ * "journalctl --sync".
+ */
+void journalSync();
+
} // namespace phosphor::logging::util