quiesce: ensure only one block per entry id
There are situations in the extensions path where a single BMC entry id
may be passed into the quiesce logic multiple times. Ensure only one
boot blocking quiesce entry is created per entry id.
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: I44dc307117370e521fa97f9b782df99cc535bf33
diff --git a/log_manager.cpp b/log_manager.cpp
index c8c6cc5..e959959 100644
--- a/log_manager.cpp
+++ b/log_manager.cpp
@@ -371,6 +371,17 @@
void Manager::quiesceOnError(const uint32_t entryId)
{
+ // Verify we don't already have this entry blocking
+ auto it = find_if(
+ this->blockingErrors.begin(), this->blockingErrors.end(),
+ [&](std::unique_ptr<Block>& obj) { return obj->entryId == entryId; });
+ if (it != this->blockingErrors.end())
+ {
+ // Already recorded so just return
+ logging::log<logging::level::DEBUG>(
+ "QuiesceOnError set and callout present but entry already logged");
+ return;
+ }
logging::log<logging::level::INFO>(
"QuiesceOnError set and callout present");
diff --git a/test/elog_quiesce_test.cpp b/test/elog_quiesce_test.cpp
index 8ec17d3..ac78974 100644
--- a/test/elog_quiesce_test.cpp
+++ b/test/elog_quiesce_test.cpp
@@ -193,6 +193,60 @@
EXPECT_EQ(manager.getEntryCallbackSize(), 0);
}
+// Test that a blocking error is only created once for an individual bmc id
+TEST_F(TestQuiesceOnError, testBlockingErrorTwice)
+{
+ uint32_t id = 100;
+ uint64_t timestamp{100};
+ std::string message{"test error"};
+ std::string fwLevel{"level42"};
+ std::vector<std::string> testData{
+ "CALLOUT_INVENTORY_PATH=/xyz/openbmc_project/inventory/system/chassis/"
+ "motherboard/powersupply0/"};
+ phosphor::logging::AssociationList associations{};
+
+ // Ensure D-Bus object created for this blocking error
+ // First allow any number of sd_bus_emit_object_added calls
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_added(testing::_, testing::_))
+ .Times(testing::AnyNumber());
+ // Second verify the new block100 object is created once
+ EXPECT_CALL(sdbusMock,
+ sd_bus_emit_object_added(
+ testing::_, testing::HasSubstr(
+ "/xyz/openbmc_project/logging/block100")))
+ .Times(1);
+
+ Entry elog{mockedBus,
+ std::string(OBJ_ENTRY) + '/' + std::to_string(id),
+ id,
+ timestamp,
+ Entry::Level::Informational,
+ std::move(message),
+ std::move(testData),
+ std::move(associations),
+ fwLevel,
+ manager};
+
+ manager.quiesceOnError(id);
+ // Created error with callout so expect a blocking error now
+ EXPECT_EQ(manager.getBlockingErrSize(), 1);
+
+ // Now pass in same ID and make sure it's ignored
+ manager.quiesceOnError(id);
+
+ // Now delete the error and make sure the object and entry go away
+ EXPECT_CALL(sdbusMock, sd_bus_emit_object_removed(testing::_, testing::_))
+ .Times(testing::AnyNumber());
+ EXPECT_CALL(sdbusMock,
+ sd_bus_emit_object_removed(
+ testing::_, testing::HasSubstr(
+ "/xyz/openbmc_project/logging/block100")))
+ .Times(1);
+
+ manager.checkAndRemoveBlockingError(id);
+ EXPECT_EQ(manager.getBlockingErrSize(), 0);
+}
+
} // namespace test
} // namespace logging
} // namespace phosphor