bmc-state: ensure bmc remains in quiesced
Recently found a bug where if a critical application fails early in the
BMC boot, the BMC state will start at Quiesced but go to Ready. This is
a bug in that once the BMC goes to Quiesced, it must remain there until
the BMC is rebooted.
The bug is that the discoverInitialState() function initially moves to
Quiesced on startup but it does not unsubscribe from systemd events so
if the failing service was not a "Requires" for multi-user.target, the
BMC state management application will get the "done" dbus event and move
from Quiesced to Ready.
Tested:
- Confirmed that BMC now remains in Quiesced when early services fail
Change-Id: Ied1a25939b324c04ae850894584daabe6f02c190
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/bmc_state_manager.cpp b/bmc_state_manager.cpp
index faab43f..849b6a8 100644
--- a/bmc_state_manager.cpp
+++ b/bmc_state_manager.cpp
@@ -44,6 +44,28 @@
constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
constexpr auto SYSTEMD_PRP_INTERFACE = "org.freedesktop.DBus.Properties";
+void BMC::bmcIsQuiesced()
+{
+ this->currentBMCState(BMCState::Quiesced);
+
+ // There is no getting out of Quiesced once entered (other then BMC
+ // reboot) so stop watching for signals
+ auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
+ SYSTEMD_INTERFACE, "Unsubscribe");
+
+ try
+ {
+ this->bus.call(method);
+ }
+ catch (const sdbusplus::exception_t& e)
+ {
+ info("Error in Unsubscribe: {ERROR}", "ERROR", e);
+ }
+
+ // disable the system state change object as well
+ this->stateSignal.reset();
+}
+
std::string BMC::getUnitState(const std::string& unitToCheck)
{
std::variant<std::string> currentState;
@@ -96,7 +118,7 @@
if (currentStateStr == activeState)
{
info("Setting the BMCState field to BMC_QUIESCED");
- this->currentBMCState(BMCState::Quiesced);
+ bmcIsQuiesced();
return;
}
@@ -187,26 +209,7 @@
if ((newStateUnit == obmcQuiesceTarget) && (newStateResult == signalDone))
{
error("BMC has entered BMC_QUIESCED state");
- this->currentBMCState(BMCState::Quiesced);
-
- // There is no getting out of Quiesced once entered (other then BMC
- // reboot) so stop watching for signals
- auto method =
- this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
- SYSTEMD_INTERFACE, "Unsubscribe");
-
- try
- {
- this->bus.call(method);
- }
- catch (const sdbusplus::exception_t& e)
- {
- info("Error in Unsubscribe: {ERROR}", "ERROR", e);
- }
-
- // disable the system state change object as well
- this->stateSignal.reset();
-
+ bmcIsQuiesced();
return 0;
}
diff --git a/bmc_state_manager.hpp b/bmc_state_manager.hpp
index 50d25f1..8c2d498 100644
--- a/bmc_state_manager.hpp
+++ b/bmc_state_manager.hpp
@@ -97,6 +97,11 @@
private:
/**
+ * @brief Put BMC into quiesced state and disable all state monitoring
+ **/
+ void bmcIsQuiesced();
+
+ /**
* @brief Retrieve input systemd unit state
**/
std::string getUnitState(const std::string& unitToCheck);