Add version to BaseBiosTable to prevent data loss
The initial version of the Base BIOS table did not support Value Display
Names (VDN). Support for VDN was introduced in a commit [1]. A BMC image
created without VDN support stores data in the old BaseBiosTable format.
If a new BMC image (with VDN support) is flashed over an older image
(without VDN support), the BIOS manager attempts to read the binary
archive generated by the older BIOS settings manager. Since it doesn't
recognize the newly added property, it assumes the persisted file is
corrupted and ignores all the saved settings.
To prevent the loss of persisted BIOS data, the versioning support
provided by the Cereal library is used. This version information is
utilized to convert the persisted data into the current supported
format.
[1]: https://github.com/openbmc/bios-settings-mgr/commit/1a448ad88fdaec7e082b4a1c437f7f3c990402cd
Change-Id: If68be37e32ae31d7338d8933df945453a30c113a
Signed-off-by: Archana Kakani <archana.kakani@ibm.com>
diff --git a/include/manager.hpp b/include/manager.hpp
index 2b79ca9..41977ca 100644
--- a/include/manager.hpp
+++ b/include/manager.hpp
@@ -49,6 +49,14 @@
std::vector<std::tuple<
BoundType, std::variant<int64_t, std::string>, std::string>>>>;
+ using oldBaseTable = std::map<
+ std::string,
+ std::tuple<AttributeType, bool, std::string, std::string, std::string,
+ std::variant<int64_t, std::string>,
+ std::variant<int64_t, std::string>,
+ std::vector<std::tuple<
+ BoundType, std::variant<int64_t, std::string>>>>>;
+
using ResetFlag = std::map<std::string, ResetFlag>;
using PendingAttributes =
@@ -124,6 +132,28 @@
*/
PendingAttributes pendingAttributes(PendingAttributes value) override;
+ /** @brief Convert the previosuly supported Base BIOS table to newly
+ * supported Base BIOS table
+ *
+ * @param[in] biosTbl - Old Base BIOS table (without VDN)
+ * @param[in] baseTable - Recently supported Base BIOS table (with VDN)
+ *
+ * @return void
+ *
+ */
+ void convertBiosDataToVersion1(Manager::oldBaseTable biosTbl,
+ Manager::BaseTable& baseTable);
+
+ /** @brief Convert the VDN supported Base BIOS table to old Base BIOS table
+ *
+ * @param[in] biosTbl - Old Base BIOS table (without VDN)
+ * @param[in] baseTable - Recently supported Base BIOS table (with VDN)
+ *
+ * @return void
+ */
+ void convertBiosDataToVersion0(Manager::oldBaseTable& baseTable,
+ Manager::BaseTable& biosTbl);
+
private:
/** @enum Index into the fields in the BaseBIOSTable
*/
diff --git a/src/manager.cpp b/src/manager.cpp
index 5dbd4dc..cfb7a4e 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -311,6 +311,80 @@
return pendingAttrs;
}
+void Manager::convertBiosDataToVersion1(Manager::oldBaseTable biosTbl,
+ Manager::BaseTable& baseTable)
+{
+ lg2::error("convertBiosDataToVersion1");
+ for (const auto& [key, baseTuple] : biosTbl)
+ {
+ const auto& vec = std::get<7>(baseTuple);
+ std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
+ std::string>>
+ dataVec;
+
+ for (const auto& [value, variantVal] : vec)
+ {
+ dataVec.emplace_back(value, variantVal,
+ ""); // Copy VDN as empty string
+ }
+
+ if (std::get<0>(baseTuple) == AttributeType::Integer)
+ {
+ baseTable[key] = std::make_tuple(
+ std::get<0>(baseTuple), std::get<1>(baseTuple),
+ std::get<2>(baseTuple), std::get<3>(baseTuple),
+ std::get<4>(baseTuple),
+ std::get<int64_t>(std::get<5>(baseTuple)),
+ std::get<int64_t>(std::get<6>(baseTuple)), dataVec);
+ }
+ else
+ {
+ baseTable[key] = std::make_tuple(
+ std::get<0>(baseTuple), std::get<1>(baseTuple),
+ std::get<2>(baseTuple), std::get<3>(baseTuple),
+ std::get<4>(baseTuple),
+ std::get<std::string>(std::get<5>(baseTuple)),
+ std::get<std::string>(std::get<6>(baseTuple)), dataVec);
+ }
+ }
+}
+
+void Manager::convertBiosDataToVersion0(Manager::oldBaseTable& baseTable,
+ Manager::BaseTable& biosTbl)
+{
+ lg2::error("convertBiosDataToVersion0");
+ for (const auto& [key, baseTuple] : biosTbl)
+ {
+ const auto& vec = std::get<7>(baseTuple);
+ std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>>>
+ dataVec;
+
+ for (const auto& [value, variantVal, vDisplayName] : vec)
+ {
+ dataVec.emplace_back(value, variantVal); // Remove VDN
+ }
+
+ if (std::get<0>(baseTuple) == AttributeType::Integer)
+ {
+ baseTable[key] = std::make_tuple(
+ std::get<0>(baseTuple), std::get<1>(baseTuple),
+ std::get<2>(baseTuple), std::get<3>(baseTuple),
+ std::get<4>(baseTuple),
+ std::get<int64_t>(std::get<5>(baseTuple)),
+ std::get<int64_t>(std::get<6>(baseTuple)), dataVec);
+ }
+ else
+ {
+ baseTable[key] = std::make_tuple(
+ std::get<0>(baseTuple), std::get<1>(baseTuple),
+ std::get<2>(baseTuple), std::get<3>(baseTuple),
+ std::get<4>(baseTuple),
+ std::get<std::string>(std::get<5>(baseTuple)),
+ std::get<std::string>(std::get<6>(baseTuple)), dataVec);
+ }
+ }
+}
+
Manager::Manager(sdbusplus::asio::object_server& objectServer,
std::shared_ptr<sdbusplus::asio::connection>& systemBus,
std::string persistPath) :
diff --git a/src/manager_serialize.cpp b/src/manager_serialize.cpp
index 473aa14..806b138 100644
--- a/src/manager_serialize.cpp
+++ b/src/manager_serialize.cpp
@@ -10,10 +10,28 @@
#include <phosphor-logging/lg2.hpp>
#include <fstream>
+#include <map>
+#include <variant>
+#include <vector>
+CEREAL_CLASS_VERSION(bios_config::Manager, 1);
namespace bios_config
{
+inline void convertBiosData(Manager& entry, Manager::BaseTable& baseTable,
+ Manager::oldBaseTable& baseTbl)
+{
+ switch (cereal::detail::Version<Manager>::version)
+ {
+ case 0:
+ entry.convertBiosDataToVersion0(baseTbl, baseTable);
+ break;
+ case 1:
+ entry.convertBiosDataToVersion1(baseTbl, baseTable);
+ break;
+ }
+}
+
/** @brief Function required by Cereal to perform serialization.
*
* @tparam Archive - Cereal archive type (binary in this case).
@@ -23,9 +41,9 @@
* across code levels
*/
template <class Archive>
-void save(Archive& archive, const Manager& entry,
- const std::uint32_t /*version*/)
+void save(Archive& archive, const Manager& entry, const std::uint32_t version)
{
+ lg2::error("Save is called with version {VER}", "VER", version);
archive(entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager::
baseBIOSTable(),
entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager::
@@ -41,14 +59,36 @@
* across code levels
*/
template <class Archive>
-void load(Archive& archive, Manager& entry, const std::uint32_t /*version*/)
+void load(Archive& archive, Manager& entry, const std::uint32_t version)
{
+ lg2::error("Load is called with version {VER}", "VER", version);
+
Manager::BaseTable baseTable;
+ Manager::oldBaseTable baseTbl;
Manager::PendingAttributes pendingAttrs;
- archive(baseTable, pendingAttrs);
+ auto currentVersion = cereal::detail::Version<Manager>::version;
+
+ switch (version)
+ {
+ case 0:
+ archive(baseTbl, pendingAttrs);
+ break;
+ case 1:
+ archive(baseTable, pendingAttrs);
+ break;
+ }
+
+ if (currentVersion != version)
+ {
+ lg2::error("Version Mismatch with saved data 1");
+ convertBiosData(entry, baseTable, baseTbl);
+ }
+
+ // Update Dbus
entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager::
baseBIOSTable(baseTable, true);
+
entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager::
pendingAttributes(pendingAttrs, true);
}