blob: 1ab774a11885727499cca63271ac26a9a392ef2e [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinler89fa0822019-07-17 13:54:30 -050016#include "repository.hpp"
17
Matt Spinlerdd325c32020-07-07 11:01:54 -050018#include <sys/stat.h>
19
Matt Spinler89fa0822019-07-17 13:54:30 -050020#include <fstream>
21#include <phosphor-logging/log.hpp>
22#include <xyz/openbmc_project/Common/File/error.hpp>
23
24namespace openpower
25{
26namespace pels
27{
28
29namespace fs = std::filesystem;
30using namespace phosphor::logging;
31namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error;
32
Matt Spinler7e727a32020-07-07 15:00:17 -050033constexpr size_t warningPercentage = 95;
34
Matt Spinlerdd325c32020-07-07 11:01:54 -050035/**
36 * @brief Returns the amount of space the file uses on disk.
37 *
38 * This is different than just the regular size of the file.
39 *
40 * @param[in] file - The file to get the size of
41 *
42 * @return size_t The disk space the file uses
43 */
44size_t getFileDiskSize(const std::filesystem::path& file)
45{
46 constexpr size_t statBlockSize = 512;
47 struct stat statData;
48 auto rc = stat(file.c_str(), &statData);
49 if (rc != 0)
50 {
51 auto e = errno;
52 std::string msg = "call to stat() failed on " + file.native() +
53 " with errno " + std::to_string(e);
54 log<level::ERR>(msg.c_str());
55 abort();
56 }
57
58 return statData.st_blocks * statBlockSize;
59}
60
Matt Spinler8d5f3a22020-07-07 10:30:33 -050061Repository::Repository(const std::filesystem::path& basePath, size_t repoSize,
62 size_t maxNumPELs) :
63 _logPath(basePath / "logs"),
64 _maxRepoSize(repoSize), _maxNumPELs(maxNumPELs)
Matt Spinler89fa0822019-07-17 13:54:30 -050065{
66 if (!fs::exists(_logPath))
67 {
68 fs::create_directories(_logPath);
69 }
Matt Spinler475e5742019-07-18 16:09:49 -050070
71 restore();
72}
73
74void Repository::restore()
75{
76 for (auto& dirEntry : fs::directory_iterator(_logPath))
77 {
78 try
79 {
80 if (!fs::is_regular_file(dirEntry.path()))
81 {
82 continue;
83 }
84
85 std::ifstream file{dirEntry.path()};
86 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
87 std::istreambuf_iterator<char>()};
88 file.close();
89
Matt Spinler07eefc52019-09-26 11:18:26 -050090 PEL pel{data};
Matt Spinler475e5742019-07-18 16:09:49 -050091 if (pel.valid())
92 {
Matt Spinlera3c12a42019-11-21 13:25:32 -060093 // If the host hasn't acked it, reset the host state so
94 // it will get sent up again.
95 if (pel.hostTransmissionState() == TransmissionState::sent)
96 {
97 pel.setHostTransmissionState(TransmissionState::newPEL);
98 try
99 {
100 write(pel, dirEntry.path());
101 }
102 catch (std::exception& e)
103 {
104 log<level::ERR>(
105 "Failed to save PEL after updating host state",
106 entry("PELID=0x%X", pel.id()));
107 }
108 }
109
Matt Spinlerdd325c32020-07-07 11:01:54 -0500110 PELAttributes attributes{dirEntry.path(),
111 getFileDiskSize(dirEntry.path()),
112 pel.privateHeader().creatorID(),
113 pel.userHeader().severity(),
114 pel.userHeader().actionFlags(),
115 pel.hostTransmissionState(),
116 pel.hmcTransmissionState()};
Matt Spinler0ff00482019-11-06 16:19:46 -0600117
Matt Spinler475e5742019-07-18 16:09:49 -0500118 using pelID = LogID::Pel;
119 using obmcID = LogID::Obmc;
Matt Spinler0ff00482019-11-06 16:19:46 -0600120 _pelAttributes.emplace(
Matt Spinler475e5742019-07-18 16:09:49 -0500121 LogID(pelID(pel.id()), obmcID(pel.obmcLogID())),
Matt Spinler0ff00482019-11-06 16:19:46 -0600122 attributes);
Matt Spinlerb188f782020-07-07 11:18:12 -0500123
124 updateRepoStats(attributes, true);
Matt Spinler475e5742019-07-18 16:09:49 -0500125 }
126 else
127 {
128 log<level::ERR>(
129 "Found invalid PEL file while restoring. Removing.",
130 entry("FILENAME=%s", dirEntry.path().c_str()));
131 fs::remove(dirEntry.path());
132 }
133 }
134 catch (std::exception& e)
135 {
136 log<level::ERR>("Hit exception while restoring PEL File",
137 entry("FILENAME=%s", dirEntry.path().c_str()),
138 entry("ERROR=%s", e.what()));
139 }
140 }
Matt Spinler89fa0822019-07-17 13:54:30 -0500141}
142
143std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time)
144{
145 char name[50];
146 sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", time.yearMSB,
147 time.yearLSB, time.month, time.day, time.hour, time.minutes,
148 time.seconds, time.hundredths, pelID);
149 return std::string{name};
150}
151
152void Repository::add(std::unique_ptr<PEL>& pel)
153{
Matt Spinlerdf43a302019-11-21 13:16:56 -0600154 pel->setHostTransmissionState(TransmissionState::newPEL);
155 pel->setHMCTransmissionState(TransmissionState::newPEL);
156
Matt Spinler89fa0822019-07-17 13:54:30 -0500157 auto path = _logPath / getPELFilename(pel->id(), pel->commitTime());
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600158
159 write(*(pel.get()), path);
160
Matt Spinlerdd325c32020-07-07 11:01:54 -0500161 PELAttributes attributes{path,
162 getFileDiskSize(path),
163 pel->privateHeader().creatorID(),
164 pel->userHeader().severity(),
165 pel->userHeader().actionFlags(),
Matt Spinler346f99a2019-11-21 13:06:35 -0600166 pel->hostTransmissionState(),
167 pel->hmcTransmissionState()};
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600168
169 using pelID = LogID::Pel;
170 using obmcID = LogID::Obmc;
171 _pelAttributes.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())),
172 attributes);
173
Matt Spinler44893cc2020-08-26 11:34:17 -0500174 _lastPelID = pel->id();
175
Matt Spinlerb188f782020-07-07 11:18:12 -0500176 updateRepoStats(attributes, true);
177
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600178 processAddCallbacks(*pel);
179}
180
181void Repository::write(const PEL& pel, const fs::path& path)
182{
Matt Spinler89fa0822019-07-17 13:54:30 -0500183 std::ofstream file{path, std::ios::binary};
184
185 if (!file.good())
186 {
187 // If this fails, the filesystem is probably full so it isn't like
188 // we could successfully create yet another error log here.
189 auto e = errno;
Matt Spinler89fa0822019-07-17 13:54:30 -0500190 fs::remove(path);
191 log<level::ERR>("Unable to open PEL file for writing",
192 entry("ERRNO=%d", e), entry("PATH=%s", path.c_str()));
193 throw file_error::Open();
194 }
195
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600196 auto data = pel.data();
Matt Spinler89fa0822019-07-17 13:54:30 -0500197 file.write(reinterpret_cast<const char*>(data.data()), data.size());
198
199 if (file.fail())
200 {
201 // Same note as above about not being able to create an error log
202 // for this case even if we wanted.
203 auto e = errno;
Matt Spinler89fa0822019-07-17 13:54:30 -0500204 file.close();
205 fs::remove(path);
206 log<level::ERR>("Unable to write PEL file", entry("ERRNO=%d", e),
207 entry("PATH=%s", path.c_str()));
208 throw file_error::Write();
209 }
Matt Spinler475e5742019-07-18 16:09:49 -0500210}
211
Matt Spinler52602e32020-07-15 12:37:28 -0500212std::optional<Repository::LogID> Repository::remove(const LogID& id)
Matt Spinler475e5742019-07-18 16:09:49 -0500213{
Matt Spinler52602e32020-07-15 12:37:28 -0500214 std::optional<LogID> actualID;
215
Matt Spinler475e5742019-07-18 16:09:49 -0500216 auto pel = findPEL(id);
Matt Spinler0ff00482019-11-06 16:19:46 -0600217 if (pel != _pelAttributes.end())
Matt Spinler475e5742019-07-18 16:09:49 -0500218 {
Matt Spinler52602e32020-07-15 12:37:28 -0500219 actualID = pel->first;
Matt Spinlerb188f782020-07-07 11:18:12 -0500220 updateRepoStats(pel->second, false);
221
Matt Spinler5f5352e2020-03-05 16:23:27 -0600222 log<level::DEBUG>("Removing PEL from repository",
223 entry("PEL_ID=0x%X", pel->first.pelID.id),
224 entry("OBMC_LOG_ID=%d", pel->first.obmcID.id));
Matt Spinler0ff00482019-11-06 16:19:46 -0600225 fs::remove(pel->second.path);
226 _pelAttributes.erase(pel);
Matt Spinler421f6532019-11-06 15:40:45 -0600227
Matt Spinler5f5352e2020-03-05 16:23:27 -0600228 processDeleteCallbacks(pel->first.pelID.id);
229 }
Matt Spinler52602e32020-07-15 12:37:28 -0500230
231 return actualID;
Matt Spinler89fa0822019-07-17 13:54:30 -0500232}
233
Matt Spinler2813f362019-07-19 12:45:28 -0500234std::optional<std::vector<uint8_t>> Repository::getPELData(const LogID& id)
235{
236 auto pel = findPEL(id);
Matt Spinler0ff00482019-11-06 16:19:46 -0600237 if (pel != _pelAttributes.end())
Matt Spinler2813f362019-07-19 12:45:28 -0500238 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600239 std::ifstream file{pel->second.path.c_str()};
Matt Spinler2813f362019-07-19 12:45:28 -0500240 if (!file.good())
241 {
242 auto e = errno;
243 log<level::ERR>("Unable to open PEL file", entry("ERRNO=%d", e),
Matt Spinler0ff00482019-11-06 16:19:46 -0600244 entry("PATH=%s", pel->second.path.c_str()));
Matt Spinler2813f362019-07-19 12:45:28 -0500245 throw file_error::Open();
246 }
247
248 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
249 std::istreambuf_iterator<char>()};
250 return data;
251 }
252
253 return std::nullopt;
254}
255
Matt Spinler6d512242019-12-09 13:44:17 -0600256std::optional<sdbusplus::message::unix_fd> Repository::getPELFD(const LogID& id)
257{
258 auto pel = findPEL(id);
259 if (pel != _pelAttributes.end())
260 {
261 FILE* fp = fopen(pel->second.path.c_str(), "rb");
262
263 if (fp == nullptr)
264 {
265 auto e = errno;
266 log<level::ERR>("Unable to open PEL File", entry("ERRNO=%d", e),
267 entry("PATH=%s", pel->second.path.c_str()));
268 throw file_error::Open();
269 }
270
271 // Must leave the file open here. It will be closed by sdbusplus
272 // when it sends it back over D-Bus.
273
274 return fileno(fp);
275 }
276 return std::nullopt;
277}
278
Matt Spinler1ea78802019-11-01 13:04:59 -0500279void Repository::for_each(ForEachFunc func) const
280{
Matt Spinler0ff00482019-11-06 16:19:46 -0600281 for (const auto& [id, attributes] : _pelAttributes)
Matt Spinler1ea78802019-11-01 13:04:59 -0500282 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600283 std::ifstream file{attributes.path};
Matt Spinler1ea78802019-11-01 13:04:59 -0500284
285 if (!file.good())
286 {
287 auto e = errno;
288 log<level::ERR>("Repository::for_each: Unable to open PEL file",
289 entry("ERRNO=%d", e),
Matt Spinler0ff00482019-11-06 16:19:46 -0600290 entry("PATH=%s", attributes.path.c_str()));
Matt Spinler1ea78802019-11-01 13:04:59 -0500291 continue;
292 }
293
294 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
295 std::istreambuf_iterator<char>()};
296 file.close();
297
298 PEL pel{data};
299
300 try
301 {
302 if (func(pel))
303 {
304 break;
305 }
306 }
307 catch (std::exception& e)
308 {
309 log<level::ERR>("Repository::for_each function exception",
310 entry("ERROR=%s", e.what()));
311 }
312 }
313}
314
Matt Spinler421f6532019-11-06 15:40:45 -0600315void Repository::processAddCallbacks(const PEL& pel) const
316{
317 for (auto& [name, func] : _addSubscriptions)
318 {
319 try
320 {
321 func(pel);
322 }
323 catch (std::exception& e)
324 {
325 log<level::ERR>("PEL Repository add callback exception",
326 entry("NAME=%s", name.c_str()),
327 entry("ERROR=%s", e.what()));
328 }
329 }
330}
331
332void Repository::processDeleteCallbacks(uint32_t id) const
333{
334 for (auto& [name, func] : _deleteSubscriptions)
335 {
336 try
337 {
338 func(id);
339 }
340 catch (std::exception& e)
341 {
342 log<level::ERR>("PEL Repository delete callback exception",
343 entry("NAME=%s", name.c_str()),
344 entry("ERROR=%s", e.what()));
345 }
346 }
347}
348
Matt Spinler0ff00482019-11-06 16:19:46 -0600349std::optional<std::reference_wrapper<const Repository::PELAttributes>>
350 Repository::getPELAttributes(const LogID& id) const
351{
352 auto pel = findPEL(id);
353 if (pel != _pelAttributes.end())
354 {
355 return pel->second;
356 }
357
358 return std::nullopt;
359}
360
Matt Spinler29d18c12019-11-21 13:31:27 -0600361void Repository::setPELHostTransState(uint32_t pelID, TransmissionState state)
362{
363 LogID id{LogID::Pel{pelID}};
364 auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
365 [&id](const auto& a) { return a.first == id; });
366
367 if ((attr != _pelAttributes.end()) && (attr->second.hostState != state))
368 {
369 PELUpdateFunc func = [state](PEL& pel) {
370 pel.setHostTransmissionState(state);
371 };
372
373 try
374 {
375 updatePEL(attr->second.path, func);
376
377 attr->second.hostState = state;
378 }
379 catch (std::exception& e)
380 {
381 log<level::ERR>("Unable to update PEL host transmission state",
382 entry("PATH=%s", attr->second.path.c_str()),
383 entry("ERROR=%s", e.what()));
384 }
385 }
386}
387
388void Repository::setPELHMCTransState(uint32_t pelID, TransmissionState state)
389{
390 LogID id{LogID::Pel{pelID}};
391 auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
392 [&id](const auto& a) { return a.first == id; });
393
394 if ((attr != _pelAttributes.end()) && (attr->second.hmcState != state))
395 {
396 PELUpdateFunc func = [state](PEL& pel) {
397 pel.setHMCTransmissionState(state);
398 };
399
400 try
401 {
402 updatePEL(attr->second.path, func);
403
404 attr->second.hmcState = state;
405 }
406 catch (std::exception& e)
407 {
408 log<level::ERR>("Unable to update PEL HMC transmission state",
409 entry("PATH=%s", attr->second.path.c_str()),
410 entry("ERROR=%s", e.what()));
411 }
412 }
413}
414
415void Repository::updatePEL(const fs::path& path, PELUpdateFunc updateFunc)
416{
417 std::ifstream file{path};
418 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
419 std::istreambuf_iterator<char>()};
420 file.close();
421
422 PEL pel{data};
423
424 if (pel.valid())
425 {
426 updateFunc(pel);
427
428 write(pel, path);
429 }
430 else
431 {
432 throw std::runtime_error(
433 "Unable to read a valid PEL when trying to update it");
434 }
435}
436
Matt Spinlerb188f782020-07-07 11:18:12 -0500437bool Repository::isServiceableSev(const PELAttributes& pel)
438{
439 auto sevType = static_cast<SeverityType>(pel.severity & 0xF0);
440 auto sevPVEntry =
441 pel_values::findByValue(pel.severity, pel_values::severityValues);
442 std::string sevName = std::get<pel_values::registryNamePos>(*sevPVEntry);
443
444 bool check1 = (sevType == SeverityType::predictive) ||
445 (sevType == SeverityType::unrecoverable) ||
446 (sevType == SeverityType::critical);
447
448 bool check2 = ((sevType == SeverityType::recovered) ||
449 (sevName == "symptom_recovered")) &&
450 !pel.actionFlags.test(hiddenFlagBit);
451
452 bool check3 = (sevName == "symptom_predictive") ||
453 (sevName == "symptom_unrecoverable") ||
454 (sevName == "symptom_critical");
455
456 return check1 || check2 || check3;
457}
458
459void Repository::updateRepoStats(const PELAttributes& pel, bool pelAdded)
460{
461 auto isServiceable = Repository::isServiceableSev(pel);
462 auto bmcPEL = CreatorID::openBMC == static_cast<CreatorID>(pel.creator);
463
464 auto adjustSize = [pelAdded, &pel](auto& runningSize) {
465 if (pelAdded)
466 {
467 runningSize += pel.sizeOnDisk;
468 }
469 else
470 {
471 runningSize = std::max(static_cast<int64_t>(runningSize) -
472 static_cast<int64_t>(pel.sizeOnDisk),
473 static_cast<int64_t>(0));
474 }
475 };
476
477 adjustSize(_sizes.total);
478
479 if (bmcPEL)
480 {
481 adjustSize(_sizes.bmc);
482 if (isServiceable)
483 {
484 adjustSize(_sizes.bmcServiceable);
485 }
486 else
487 {
488 adjustSize(_sizes.bmcInfo);
489 }
490 }
491 else
492 {
493 adjustSize(_sizes.nonBMC);
494 if (isServiceable)
495 {
496 adjustSize(_sizes.nonBMCServiceable);
497 }
498 else
499 {
500 adjustSize(_sizes.nonBMCInfo);
501 }
502 }
503}
504
Matt Spinler7e727a32020-07-07 15:00:17 -0500505bool Repository::sizeWarning() const
506{
507 return (_sizes.total > (_maxRepoSize * warningPercentage / 100)) ||
508 (_pelAttributes.size() > _maxNumPELs);
509}
510
Matt Spinlerb0a8df52020-07-07 14:41:06 -0500511std::vector<Repository::AttributesReference>
512 Repository::getAllPELAttributes(SortOrder order) const
513{
514 std::vector<Repository::AttributesReference> attributes;
515
516 std::for_each(
517 _pelAttributes.begin(), _pelAttributes.end(),
518 [&attributes](auto& pelEntry) { attributes.push_back(pelEntry); });
519
520 std::sort(attributes.begin(), attributes.end(),
521 [order](const auto& left, const auto& right) {
522 if (order == SortOrder::ascending)
523 {
524 return left.get().second.path < right.get().second.path;
525 }
526 return left.get().second.path > right.get().second.path;
527 });
528
529 return attributes;
530}
531
532std::vector<uint32_t> Repository::prune()
533{
534 std::vector<uint32_t> obmcLogIDs;
535 std::string msg = "Pruning PEL repository that takes up " +
536 std::to_string(_sizes.total) + " bytes and has " +
537 std::to_string(_pelAttributes.size()) + " PELs";
538 log<level::INFO>(msg.c_str());
539
540 // Set up the 5 functions to check if the PEL category
541 // is still over its limits.
542
543 // BMC informational PELs should only take up 15%
544 IsOverLimitFunc overBMCInfoLimit = [this]() {
545 return _sizes.bmcInfo > _maxRepoSize * 15 / 100;
546 };
547
548 // BMC non informational PELs should only take up 30%
549 IsOverLimitFunc overBMCNonInfoLimit = [this]() {
550 return _sizes.bmcServiceable > _maxRepoSize * 30 / 100;
551 };
552
553 // Non BMC informational PELs should only take up 15%
554 IsOverLimitFunc overNonBMCInfoLimit = [this]() {
555 return _sizes.nonBMCInfo > _maxRepoSize * 15 / 100;
556 };
557
558 // Non BMC non informational PELs should only take up 15%
559 IsOverLimitFunc overNonBMCNonInfoLimit = [this]() {
560 return _sizes.nonBMCServiceable > _maxRepoSize * 30 / 100;
561 };
562
563 // Bring the total number of PELs down to 80% of the max
564 IsOverLimitFunc tooManyPELsLimit = [this]() {
565 return _pelAttributes.size() > _maxNumPELs * 80 / 100;
566 };
567
568 // Set up the functions to determine which category a PEL is in.
569 // TODO: Return false in these functions if a PEL caused a guard record.
570
571 // A BMC informational PEL
572 IsPELTypeFunc isBMCInfo = [](const PELAttributes& pel) {
573 return (CreatorID::openBMC == static_cast<CreatorID>(pel.creator)) &&
574 !Repository::isServiceableSev(pel);
575 };
576
577 // A BMC non informational PEL
578 IsPELTypeFunc isBMCNonInfo = [](const PELAttributes& pel) {
579 return (CreatorID::openBMC == static_cast<CreatorID>(pel.creator)) &&
580 Repository::isServiceableSev(pel);
581 };
582
583 // A non BMC informational PEL
584 IsPELTypeFunc isNonBMCInfo = [](const PELAttributes& pel) {
585 return (CreatorID::openBMC != static_cast<CreatorID>(pel.creator)) &&
586 !Repository::isServiceableSev(pel);
587 };
588
589 // A non BMC non informational PEL
590 IsPELTypeFunc isNonBMCNonInfo = [](const PELAttributes& pel) {
591 return (CreatorID::openBMC != static_cast<CreatorID>(pel.creator)) &&
592 Repository::isServiceableSev(pel);
593 };
594
595 // When counting PELs, count every PEL
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500596 IsPELTypeFunc isAnyPEL = [](const PELAttributes& /*pel*/) { return true; };
Matt Spinlerb0a8df52020-07-07 14:41:06 -0500597
598 // Check all 4 categories, which will result in at most 90%
599 // usage (15 + 30 + 15 + 30).
600 removePELs(overBMCInfoLimit, isBMCInfo, obmcLogIDs);
601 removePELs(overBMCNonInfoLimit, isBMCNonInfo, obmcLogIDs);
602 removePELs(overNonBMCInfoLimit, isNonBMCInfo, obmcLogIDs);
603 removePELs(overNonBMCNonInfoLimit, isNonBMCNonInfo, obmcLogIDs);
604
605 // After the above pruning check if there are still too many PELs,
606 // which can happen depending on PEL sizes.
607 if (_pelAttributes.size() > _maxNumPELs)
608 {
609 removePELs(tooManyPELsLimit, isAnyPEL, obmcLogIDs);
610 }
611
612 if (!obmcLogIDs.empty())
613 {
614 std::string msg = "Number of PELs removed to save space: " +
615 std::to_string(obmcLogIDs.size());
616 log<level::INFO>(msg.c_str());
617 }
618
619 return obmcLogIDs;
620}
621
622void Repository::removePELs(IsOverLimitFunc& isOverLimit,
623 IsPELTypeFunc& isPELType,
624 std::vector<uint32_t>& removedBMCLogIDs)
625{
626 if (!isOverLimit())
627 {
628 return;
629 }
630
631 auto attributes = getAllPELAttributes(SortOrder::ascending);
632
633 // Make 4 passes on the PELs, stopping as soon as isOverLimit
634 // returns false.
635 // Pass 1: only delete HMC acked PELs
636 // Pass 2: only delete OS acked PELs
637 // Pass 3: only delete PHYP sent PELs
638 // Pass 4: delete all PELs
639 static const std::vector<std::function<bool(const PELAttributes& pel)>>
640 stateChecks{[](const auto& pel) {
641 return pel.hmcState == TransmissionState::acked;
642 },
643
644 [](const auto& pel) {
645 return pel.hostState == TransmissionState::acked;
646 },
647
648 [](const auto& pel) {
649 return pel.hostState == TransmissionState::sent;
650 },
651
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500652 [](const auto& /*pel*/) { return true; }};
Matt Spinlerb0a8df52020-07-07 14:41:06 -0500653
654 for (const auto& stateCheck : stateChecks)
655 {
656 for (auto it = attributes.begin(); it != attributes.end();)
657 {
658 const auto& pel = it->get();
659 if (isPELType(pel.second) && stateCheck(pel.second))
660 {
661 auto removedID = pel.first.obmcID.id;
662 remove(pel.first);
663
664 removedBMCLogIDs.push_back(removedID);
665
666 attributes.erase(it);
667
668 if (!isOverLimit())
669 {
670 break;
671 }
672 }
673 else
674 {
675 ++it;
676 }
677 }
678
679 if (!isOverLimit())
680 {
681 break;
682 }
683 }
684}
685
Matt Spinler89fa0822019-07-17 13:54:30 -0500686} // namespace pels
687} // namespace openpower