1 #include "config.h" 2 3 #include "dump_manager_system.hpp" 4 5 #include "dump_utils.hpp" 6 #include "op_dump_consts.hpp" 7 #include "system_dump_entry.hpp" 8 #include "xyz/openbmc_project/Common/error.hpp" 9 10 #include <phosphor-logging/elog-errors.hpp> 11 #include <phosphor-logging/elog.hpp> 12 #include <phosphor-logging/lg2.hpp> 13 14 namespace openpower 15 { 16 namespace dump 17 { 18 namespace system 19 { 20 21 using namespace phosphor::logging; 22 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 23 24 void Manager::notify(uint32_t dumpId, uint64_t size) 25 { 26 // Get the timestamp 27 uint64_t timeStamp = 28 std::chrono::duration_cast<std::chrono::microseconds>( 29 std::chrono::system_clock::now().time_since_epoch()) 30 .count(); 31 32 // A system dump can be created due to a fault in the server or by a user 33 // request. A system dump by fault is first reported here, but for a 34 // user-requested dump, an entry will be created first with an invalid 35 // source id. Since only one system dump creation is allowed at a time, if 36 // there's an entry with an invalid sourceId, we will update that entry. 37 openpower::dump::system::Entry* upEntry = nullptr; 38 for (auto& entry : entries) 39 { 40 openpower::dump::system::Entry* sysEntry = 41 dynamic_cast<openpower::dump::system::Entry*>(entry.second.get()); 42 43 // If there's already a completed entry with the input source id and 44 // size, ignore this notification 45 if ((sysEntry->sourceDumpId() == dumpId) && (sysEntry->size() == size)) 46 { 47 if (sysEntry->status() == 48 phosphor::dump::OperationStatus::Completed) 49 { 50 lg2::info( 51 "System dump entry with source dump id:{SOURCE_ID} and " 52 "size: {SIZE} is already present with entry id:{ID}", 53 "SOURCE_ID", dumpId, "SIZE", size, "ID", 54 sysEntry->getDumpId()); 55 return; 56 } 57 else 58 { 59 lg2::error("A duplicate notification for an incomplete dump " 60 "dump id: {SOURCE_ID} entry id: {ID}", 61 "SOURCE_D", dumpId, "ID", sysEntry->getDumpId()); 62 upEntry = sysEntry; 63 break; 64 } 65 } 66 else if (sysEntry->sourceDumpId() == dumpId) 67 { 68 // If the dump id is the same but the size is different, then this 69 // is a new dump. So, delete the stale entry and prepare to create a 70 // new one. 71 lg2::info("A previous dump entry found with same source id: " 72 "{SOURCE_ID}, deleting it, entry id: {DUMP_ID}", 73 "SOURCE_ID", dumpId, "DUMP_ID", sysEntry->getDumpId()); 74 sysEntry->delete_(); 75 // No 'break' here, as we need to continue checking other entries. 76 } 77 78 // Save the first entry with INVALID_SOURCE_ID, but continue in the loop 79 // to ensure the new entry is not a duplicate. 80 if ((sysEntry->sourceDumpId() == INVALID_SOURCE_ID) && 81 (upEntry == nullptr)) 82 { 83 upEntry = sysEntry; 84 } 85 } 86 87 if (upEntry != nullptr) 88 { 89 lg2::info( 90 "System Dump Notify: Updating dumpId:{ID} Source Id:{SOURCE_ID} " 91 "Size:{SIZE}", 92 "ID", upEntry->getDumpId(), "SOURCE_ID", dumpId, "SIZE", size); 93 upEntry->update(timeStamp, size, dumpId); 94 return; 95 } 96 97 // Get the id 98 auto id = lastEntryId + 1; 99 auto idString = std::to_string(id); 100 auto objPath = std::filesystem::path(baseEntryPath) / idString; 101 102 // TODO: Get the originator Id, Type from the persisted file. 103 // For now replacing it with null 104 try 105 { 106 lg2::info("System Dump Notify: creating new dump " 107 "entry dumpId:{ID} Source Id:{SOURCE_ID} Size:{SIZE}", 108 "ID", id, "SOURCE_ID", dumpId, "SIZE", size); 109 entries.insert(std::make_pair( 110 id, std::make_unique<system::Entry>( 111 bus, objPath.c_str(), id, timeStamp, size, dumpId, 112 phosphor::dump::OperationStatus::Completed, std::string(), 113 originatorTypes::Internal, *this))); 114 } 115 catch (const std::invalid_argument& e) 116 { 117 lg2::error( 118 "Error in creating system dump entry, errormsg: {ERROR}, " 119 "OBJECTPATH: {OBJECT_PATH}, ID: {ID}, TIMESTAMP: {TIMESTAMP}, " 120 "SIZE: {SIZE}, SOURCEID: {SOURCE_ID}", 121 "ERROR", e, "OBJECT_PATH", objPath, "ID", id, "TIMESTAMP", 122 timeStamp, "SIZE", size, "SOURCE_ID", dumpId); 123 report<InternalFailure>(); 124 return; 125 } 126 lastEntryId++; 127 return; 128 } 129 130 sdbusplus::message::object_path 131 Manager::createDump(phosphor::dump::DumpCreateParams params) 132 { 133 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 134 constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 135 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 136 constexpr auto DIAG_MOD_TARGET = "obmc-host-crash@0.target"; 137 138 if (params.size() > CREATE_DUMP_MAX_PARAMS) 139 { 140 lg2::warning( 141 "System dump accepts not more than 2 additional parameters"); 142 } 143 144 using NotAllowed = 145 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 146 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON; 147 148 // Allow creating system dump only when the host is up. 149 if (!phosphor::dump::isHostRunning()) 150 { 151 elog<NotAllowed>( 152 Reason("System dump can be initiated only when the host is up")); 153 return std::string(); 154 } 155 156 // Get the originator id and type from params 157 std::string originatorId; 158 originatorTypes originatorType; 159 160 phosphor::dump::extractOriginatorProperties(params, originatorId, 161 originatorType); 162 163 auto b = sdbusplus::bus::new_default(); 164 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, 165 SYSTEMD_INTERFACE, "StartUnit"); 166 method.append(DIAG_MOD_TARGET); // unit to activate 167 method.append("replace"); 168 bus.call_noreply(method); 169 170 auto id = lastEntryId + 1; 171 auto idString = std::to_string(id); 172 auto objPath = std::filesystem::path(baseEntryPath) / idString; 173 uint64_t timeStamp = 174 std::chrono::duration_cast<std::chrono::microseconds>( 175 std::chrono::system_clock::now().time_since_epoch()) 176 .count(); 177 178 try 179 { 180 entries.insert(std::make_pair( 181 id, std::make_unique<system::Entry>( 182 bus, objPath.c_str(), id, timeStamp, 0, INVALID_SOURCE_ID, 183 phosphor::dump::OperationStatus::InProgress, originatorId, 184 originatorType, *this))); 185 } 186 catch (const std::invalid_argument& e) 187 { 188 lg2::error("Error in creating system dump entry, errormsg: {ERROR}, " 189 "OBJECTPATH: {OBJECT_PATH}, ID: {ID}", 190 "ERROR", e, "OBJECT_PATH", objPath, "ID", id); 191 elog<InternalFailure>(); 192 return std::string(); 193 } 194 lastEntryId++; 195 return objPath.string(); 196 } 197 198 } // namespace system 199 } // namespace dump 200 } // namespace openpower 201