blob: e6089274f1fcb7a0c2935335d23cd8f4d6d8f456 [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 Spinlerdd325c32020-07-07 11:01:54 -050033/**
34 * @brief Returns the amount of space the file uses on disk.
35 *
36 * This is different than just the regular size of the file.
37 *
38 * @param[in] file - The file to get the size of
39 *
40 * @return size_t The disk space the file uses
41 */
42size_t getFileDiskSize(const std::filesystem::path& file)
43{
44 constexpr size_t statBlockSize = 512;
45 struct stat statData;
46 auto rc = stat(file.c_str(), &statData);
47 if (rc != 0)
48 {
49 auto e = errno;
50 std::string msg = "call to stat() failed on " + file.native() +
51 " with errno " + std::to_string(e);
52 log<level::ERR>(msg.c_str());
53 abort();
54 }
55
56 return statData.st_blocks * statBlockSize;
57}
58
Matt Spinler8d5f3a22020-07-07 10:30:33 -050059Repository::Repository(const std::filesystem::path& basePath, size_t repoSize,
60 size_t maxNumPELs) :
61 _logPath(basePath / "logs"),
62 _maxRepoSize(repoSize), _maxNumPELs(maxNumPELs)
Matt Spinler89fa0822019-07-17 13:54:30 -050063{
64 if (!fs::exists(_logPath))
65 {
66 fs::create_directories(_logPath);
67 }
Matt Spinler475e5742019-07-18 16:09:49 -050068
69 restore();
70}
71
72void Repository::restore()
73{
74 for (auto& dirEntry : fs::directory_iterator(_logPath))
75 {
76 try
77 {
78 if (!fs::is_regular_file(dirEntry.path()))
79 {
80 continue;
81 }
82
83 std::ifstream file{dirEntry.path()};
84 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
85 std::istreambuf_iterator<char>()};
86 file.close();
87
Matt Spinler07eefc52019-09-26 11:18:26 -050088 PEL pel{data};
Matt Spinler475e5742019-07-18 16:09:49 -050089 if (pel.valid())
90 {
Matt Spinlera3c12a42019-11-21 13:25:32 -060091 // If the host hasn't acked it, reset the host state so
92 // it will get sent up again.
93 if (pel.hostTransmissionState() == TransmissionState::sent)
94 {
95 pel.setHostTransmissionState(TransmissionState::newPEL);
96 try
97 {
98 write(pel, dirEntry.path());
99 }
100 catch (std::exception& e)
101 {
102 log<level::ERR>(
103 "Failed to save PEL after updating host state",
104 entry("PELID=0x%X", pel.id()));
105 }
106 }
107
Matt Spinlerdd325c32020-07-07 11:01:54 -0500108 PELAttributes attributes{dirEntry.path(),
109 getFileDiskSize(dirEntry.path()),
110 pel.privateHeader().creatorID(),
111 pel.userHeader().severity(),
112 pel.userHeader().actionFlags(),
113 pel.hostTransmissionState(),
114 pel.hmcTransmissionState()};
Matt Spinler0ff00482019-11-06 16:19:46 -0600115
Matt Spinler475e5742019-07-18 16:09:49 -0500116 using pelID = LogID::Pel;
117 using obmcID = LogID::Obmc;
Matt Spinler0ff00482019-11-06 16:19:46 -0600118 _pelAttributes.emplace(
Matt Spinler475e5742019-07-18 16:09:49 -0500119 LogID(pelID(pel.id()), obmcID(pel.obmcLogID())),
Matt Spinler0ff00482019-11-06 16:19:46 -0600120 attributes);
Matt Spinlerb188f782020-07-07 11:18:12 -0500121
122 updateRepoStats(attributes, true);
Matt Spinler475e5742019-07-18 16:09:49 -0500123 }
124 else
125 {
126 log<level::ERR>(
127 "Found invalid PEL file while restoring. Removing.",
128 entry("FILENAME=%s", dirEntry.path().c_str()));
129 fs::remove(dirEntry.path());
130 }
131 }
132 catch (std::exception& e)
133 {
134 log<level::ERR>("Hit exception while restoring PEL File",
135 entry("FILENAME=%s", dirEntry.path().c_str()),
136 entry("ERROR=%s", e.what()));
137 }
138 }
Matt Spinler89fa0822019-07-17 13:54:30 -0500139}
140
141std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time)
142{
143 char name[50];
144 sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", time.yearMSB,
145 time.yearLSB, time.month, time.day, time.hour, time.minutes,
146 time.seconds, time.hundredths, pelID);
147 return std::string{name};
148}
149
150void Repository::add(std::unique_ptr<PEL>& pel)
151{
Matt Spinlerdf43a302019-11-21 13:16:56 -0600152 pel->setHostTransmissionState(TransmissionState::newPEL);
153 pel->setHMCTransmissionState(TransmissionState::newPEL);
154
Matt Spinler89fa0822019-07-17 13:54:30 -0500155 auto path = _logPath / getPELFilename(pel->id(), pel->commitTime());
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600156
157 write(*(pel.get()), path);
158
Matt Spinlerdd325c32020-07-07 11:01:54 -0500159 PELAttributes attributes{path,
160 getFileDiskSize(path),
161 pel->privateHeader().creatorID(),
162 pel->userHeader().severity(),
163 pel->userHeader().actionFlags(),
Matt Spinler346f99a2019-11-21 13:06:35 -0600164 pel->hostTransmissionState(),
165 pel->hmcTransmissionState()};
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600166
167 using pelID = LogID::Pel;
168 using obmcID = LogID::Obmc;
169 _pelAttributes.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())),
170 attributes);
171
Matt Spinlerb188f782020-07-07 11:18:12 -0500172 updateRepoStats(attributes, true);
173
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600174 processAddCallbacks(*pel);
175}
176
177void Repository::write(const PEL& pel, const fs::path& path)
178{
Matt Spinler89fa0822019-07-17 13:54:30 -0500179 std::ofstream file{path, std::ios::binary};
180
181 if (!file.good())
182 {
183 // If this fails, the filesystem is probably full so it isn't like
184 // we could successfully create yet another error log here.
185 auto e = errno;
Matt Spinler89fa0822019-07-17 13:54:30 -0500186 fs::remove(path);
187 log<level::ERR>("Unable to open PEL file for writing",
188 entry("ERRNO=%d", e), entry("PATH=%s", path.c_str()));
189 throw file_error::Open();
190 }
191
Matt Spinlerab1b97f2019-11-07 13:38:07 -0600192 auto data = pel.data();
Matt Spinler89fa0822019-07-17 13:54:30 -0500193 file.write(reinterpret_cast<const char*>(data.data()), data.size());
194
195 if (file.fail())
196 {
197 // Same note as above about not being able to create an error log
198 // for this case even if we wanted.
199 auto e = errno;
Matt Spinler89fa0822019-07-17 13:54:30 -0500200 file.close();
201 fs::remove(path);
202 log<level::ERR>("Unable to write PEL file", entry("ERRNO=%d", e),
203 entry("PATH=%s", path.c_str()));
204 throw file_error::Write();
205 }
Matt Spinler475e5742019-07-18 16:09:49 -0500206}
207
208void Repository::remove(const LogID& id)
209{
210 auto pel = findPEL(id);
Matt Spinler0ff00482019-11-06 16:19:46 -0600211 if (pel != _pelAttributes.end())
Matt Spinler475e5742019-07-18 16:09:49 -0500212 {
Matt Spinlerb188f782020-07-07 11:18:12 -0500213 updateRepoStats(pel->second, false);
214
Matt Spinler5f5352e2020-03-05 16:23:27 -0600215 log<level::DEBUG>("Removing PEL from repository",
216 entry("PEL_ID=0x%X", pel->first.pelID.id),
217 entry("OBMC_LOG_ID=%d", pel->first.obmcID.id));
Matt Spinler0ff00482019-11-06 16:19:46 -0600218 fs::remove(pel->second.path);
219 _pelAttributes.erase(pel);
Matt Spinler421f6532019-11-06 15:40:45 -0600220
Matt Spinler5f5352e2020-03-05 16:23:27 -0600221 processDeleteCallbacks(pel->first.pelID.id);
222 }
223 else
224 {
225 log<level::DEBUG>("Could not find PEL to remove",
226 entry("PEL_ID=0x%X", id.pelID.id),
227 entry("OBMC_LOG_ID=%d", id.obmcID.id));
Matt Spinler475e5742019-07-18 16:09:49 -0500228 }
Matt Spinler89fa0822019-07-17 13:54:30 -0500229}
230
Matt Spinler2813f362019-07-19 12:45:28 -0500231std::optional<std::vector<uint8_t>> Repository::getPELData(const LogID& id)
232{
233 auto pel = findPEL(id);
Matt Spinler0ff00482019-11-06 16:19:46 -0600234 if (pel != _pelAttributes.end())
Matt Spinler2813f362019-07-19 12:45:28 -0500235 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600236 std::ifstream file{pel->second.path.c_str()};
Matt Spinler2813f362019-07-19 12:45:28 -0500237 if (!file.good())
238 {
239 auto e = errno;
240 log<level::ERR>("Unable to open PEL file", entry("ERRNO=%d", e),
Matt Spinler0ff00482019-11-06 16:19:46 -0600241 entry("PATH=%s", pel->second.path.c_str()));
Matt Spinler2813f362019-07-19 12:45:28 -0500242 throw file_error::Open();
243 }
244
245 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
246 std::istreambuf_iterator<char>()};
247 return data;
248 }
249
250 return std::nullopt;
251}
252
Matt Spinler6d512242019-12-09 13:44:17 -0600253std::optional<sdbusplus::message::unix_fd> Repository::getPELFD(const LogID& id)
254{
255 auto pel = findPEL(id);
256 if (pel != _pelAttributes.end())
257 {
258 FILE* fp = fopen(pel->second.path.c_str(), "rb");
259
260 if (fp == nullptr)
261 {
262 auto e = errno;
263 log<level::ERR>("Unable to open PEL File", entry("ERRNO=%d", e),
264 entry("PATH=%s", pel->second.path.c_str()));
265 throw file_error::Open();
266 }
267
268 // Must leave the file open here. It will be closed by sdbusplus
269 // when it sends it back over D-Bus.
270
271 return fileno(fp);
272 }
273 return std::nullopt;
274}
275
Matt Spinler1ea78802019-11-01 13:04:59 -0500276void Repository::for_each(ForEachFunc func) const
277{
Matt Spinler0ff00482019-11-06 16:19:46 -0600278 for (const auto& [id, attributes] : _pelAttributes)
Matt Spinler1ea78802019-11-01 13:04:59 -0500279 {
Matt Spinler0ff00482019-11-06 16:19:46 -0600280 std::ifstream file{attributes.path};
Matt Spinler1ea78802019-11-01 13:04:59 -0500281
282 if (!file.good())
283 {
284 auto e = errno;
285 log<level::ERR>("Repository::for_each: Unable to open PEL file",
286 entry("ERRNO=%d", e),
Matt Spinler0ff00482019-11-06 16:19:46 -0600287 entry("PATH=%s", attributes.path.c_str()));
Matt Spinler1ea78802019-11-01 13:04:59 -0500288 continue;
289 }
290
291 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
292 std::istreambuf_iterator<char>()};
293 file.close();
294
295 PEL pel{data};
296
297 try
298 {
299 if (func(pel))
300 {
301 break;
302 }
303 }
304 catch (std::exception& e)
305 {
306 log<level::ERR>("Repository::for_each function exception",
307 entry("ERROR=%s", e.what()));
308 }
309 }
310}
311
Matt Spinler421f6532019-11-06 15:40:45 -0600312void Repository::processAddCallbacks(const PEL& pel) const
313{
314 for (auto& [name, func] : _addSubscriptions)
315 {
316 try
317 {
318 func(pel);
319 }
320 catch (std::exception& e)
321 {
322 log<level::ERR>("PEL Repository add callback exception",
323 entry("NAME=%s", name.c_str()),
324 entry("ERROR=%s", e.what()));
325 }
326 }
327}
328
329void Repository::processDeleteCallbacks(uint32_t id) const
330{
331 for (auto& [name, func] : _deleteSubscriptions)
332 {
333 try
334 {
335 func(id);
336 }
337 catch (std::exception& e)
338 {
339 log<level::ERR>("PEL Repository delete callback exception",
340 entry("NAME=%s", name.c_str()),
341 entry("ERROR=%s", e.what()));
342 }
343 }
344}
345
Matt Spinler0ff00482019-11-06 16:19:46 -0600346std::optional<std::reference_wrapper<const Repository::PELAttributes>>
347 Repository::getPELAttributes(const LogID& id) const
348{
349 auto pel = findPEL(id);
350 if (pel != _pelAttributes.end())
351 {
352 return pel->second;
353 }
354
355 return std::nullopt;
356}
357
Matt Spinler29d18c12019-11-21 13:31:27 -0600358void Repository::setPELHostTransState(uint32_t pelID, TransmissionState state)
359{
360 LogID id{LogID::Pel{pelID}};
361 auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
362 [&id](const auto& a) { return a.first == id; });
363
364 if ((attr != _pelAttributes.end()) && (attr->second.hostState != state))
365 {
366 PELUpdateFunc func = [state](PEL& pel) {
367 pel.setHostTransmissionState(state);
368 };
369
370 try
371 {
372 updatePEL(attr->second.path, func);
373
374 attr->second.hostState = state;
375 }
376 catch (std::exception& e)
377 {
378 log<level::ERR>("Unable to update PEL host transmission state",
379 entry("PATH=%s", attr->second.path.c_str()),
380 entry("ERROR=%s", e.what()));
381 }
382 }
383}
384
385void Repository::setPELHMCTransState(uint32_t pelID, TransmissionState state)
386{
387 LogID id{LogID::Pel{pelID}};
388 auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
389 [&id](const auto& a) { return a.first == id; });
390
391 if ((attr != _pelAttributes.end()) && (attr->second.hmcState != state))
392 {
393 PELUpdateFunc func = [state](PEL& pel) {
394 pel.setHMCTransmissionState(state);
395 };
396
397 try
398 {
399 updatePEL(attr->second.path, func);
400
401 attr->second.hmcState = state;
402 }
403 catch (std::exception& e)
404 {
405 log<level::ERR>("Unable to update PEL HMC transmission state",
406 entry("PATH=%s", attr->second.path.c_str()),
407 entry("ERROR=%s", e.what()));
408 }
409 }
410}
411
412void Repository::updatePEL(const fs::path& path, PELUpdateFunc updateFunc)
413{
414 std::ifstream file{path};
415 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
416 std::istreambuf_iterator<char>()};
417 file.close();
418
419 PEL pel{data};
420
421 if (pel.valid())
422 {
423 updateFunc(pel);
424
425 write(pel, path);
426 }
427 else
428 {
429 throw std::runtime_error(
430 "Unable to read a valid PEL when trying to update it");
431 }
432}
433
Matt Spinlerb188f782020-07-07 11:18:12 -0500434bool Repository::isServiceableSev(const PELAttributes& pel)
435{
436 auto sevType = static_cast<SeverityType>(pel.severity & 0xF0);
437 auto sevPVEntry =
438 pel_values::findByValue(pel.severity, pel_values::severityValues);
439 std::string sevName = std::get<pel_values::registryNamePos>(*sevPVEntry);
440
441 bool check1 = (sevType == SeverityType::predictive) ||
442 (sevType == SeverityType::unrecoverable) ||
443 (sevType == SeverityType::critical);
444
445 bool check2 = ((sevType == SeverityType::recovered) ||
446 (sevName == "symptom_recovered")) &&
447 !pel.actionFlags.test(hiddenFlagBit);
448
449 bool check3 = (sevName == "symptom_predictive") ||
450 (sevName == "symptom_unrecoverable") ||
451 (sevName == "symptom_critical");
452
453 return check1 || check2 || check3;
454}
455
456void Repository::updateRepoStats(const PELAttributes& pel, bool pelAdded)
457{
458 auto isServiceable = Repository::isServiceableSev(pel);
459 auto bmcPEL = CreatorID::openBMC == static_cast<CreatorID>(pel.creator);
460
461 auto adjustSize = [pelAdded, &pel](auto& runningSize) {
462 if (pelAdded)
463 {
464 runningSize += pel.sizeOnDisk;
465 }
466 else
467 {
468 runningSize = std::max(static_cast<int64_t>(runningSize) -
469 static_cast<int64_t>(pel.sizeOnDisk),
470 static_cast<int64_t>(0));
471 }
472 };
473
474 adjustSize(_sizes.total);
475
476 if (bmcPEL)
477 {
478 adjustSize(_sizes.bmc);
479 if (isServiceable)
480 {
481 adjustSize(_sizes.bmcServiceable);
482 }
483 else
484 {
485 adjustSize(_sizes.bmcInfo);
486 }
487 }
488 else
489 {
490 adjustSize(_sizes.nonBMC);
491 if (isServiceable)
492 {
493 adjustSize(_sizes.nonBMCServiceable);
494 }
495 else
496 {
497 adjustSize(_sizes.nonBMCInfo);
498 }
499 }
500}
501
Matt Spinlerb0a8df52020-07-07 14:41:06 -0500502std::vector<Repository::AttributesReference>
503 Repository::getAllPELAttributes(SortOrder order) const
504{
505 std::vector<Repository::AttributesReference> attributes;
506
507 std::for_each(
508 _pelAttributes.begin(), _pelAttributes.end(),
509 [&attributes](auto& pelEntry) { attributes.push_back(pelEntry); });
510
511 std::sort(attributes.begin(), attributes.end(),
512 [order](const auto& left, const auto& right) {
513 if (order == SortOrder::ascending)
514 {
515 return left.get().second.path < right.get().second.path;
516 }
517 return left.get().second.path > right.get().second.path;
518 });
519
520 return attributes;
521}
522
523std::vector<uint32_t> Repository::prune()
524{
525 std::vector<uint32_t> obmcLogIDs;
526 std::string msg = "Pruning PEL repository that takes up " +
527 std::to_string(_sizes.total) + " bytes and has " +
528 std::to_string(_pelAttributes.size()) + " PELs";
529 log<level::INFO>(msg.c_str());
530
531 // Set up the 5 functions to check if the PEL category
532 // is still over its limits.
533
534 // BMC informational PELs should only take up 15%
535 IsOverLimitFunc overBMCInfoLimit = [this]() {
536 return _sizes.bmcInfo > _maxRepoSize * 15 / 100;
537 };
538
539 // BMC non informational PELs should only take up 30%
540 IsOverLimitFunc overBMCNonInfoLimit = [this]() {
541 return _sizes.bmcServiceable > _maxRepoSize * 30 / 100;
542 };
543
544 // Non BMC informational PELs should only take up 15%
545 IsOverLimitFunc overNonBMCInfoLimit = [this]() {
546 return _sizes.nonBMCInfo > _maxRepoSize * 15 / 100;
547 };
548
549 // Non BMC non informational PELs should only take up 15%
550 IsOverLimitFunc overNonBMCNonInfoLimit = [this]() {
551 return _sizes.nonBMCServiceable > _maxRepoSize * 30 / 100;
552 };
553
554 // Bring the total number of PELs down to 80% of the max
555 IsOverLimitFunc tooManyPELsLimit = [this]() {
556 return _pelAttributes.size() > _maxNumPELs * 80 / 100;
557 };
558
559 // Set up the functions to determine which category a PEL is in.
560 // TODO: Return false in these functions if a PEL caused a guard record.
561
562 // A BMC informational PEL
563 IsPELTypeFunc isBMCInfo = [](const PELAttributes& pel) {
564 return (CreatorID::openBMC == static_cast<CreatorID>(pel.creator)) &&
565 !Repository::isServiceableSev(pel);
566 };
567
568 // A BMC non informational PEL
569 IsPELTypeFunc isBMCNonInfo = [](const PELAttributes& pel) {
570 return (CreatorID::openBMC == static_cast<CreatorID>(pel.creator)) &&
571 Repository::isServiceableSev(pel);
572 };
573
574 // A non BMC informational PEL
575 IsPELTypeFunc isNonBMCInfo = [](const PELAttributes& pel) {
576 return (CreatorID::openBMC != static_cast<CreatorID>(pel.creator)) &&
577 !Repository::isServiceableSev(pel);
578 };
579
580 // A non BMC non informational PEL
581 IsPELTypeFunc isNonBMCNonInfo = [](const PELAttributes& pel) {
582 return (CreatorID::openBMC != static_cast<CreatorID>(pel.creator)) &&
583 Repository::isServiceableSev(pel);
584 };
585
586 // When counting PELs, count every PEL
587 IsPELTypeFunc isAnyPEL = [](const PELAttributes& pel) { return true; };
588
589 // Check all 4 categories, which will result in at most 90%
590 // usage (15 + 30 + 15 + 30).
591 removePELs(overBMCInfoLimit, isBMCInfo, obmcLogIDs);
592 removePELs(overBMCNonInfoLimit, isBMCNonInfo, obmcLogIDs);
593 removePELs(overNonBMCInfoLimit, isNonBMCInfo, obmcLogIDs);
594 removePELs(overNonBMCNonInfoLimit, isNonBMCNonInfo, obmcLogIDs);
595
596 // After the above pruning check if there are still too many PELs,
597 // which can happen depending on PEL sizes.
598 if (_pelAttributes.size() > _maxNumPELs)
599 {
600 removePELs(tooManyPELsLimit, isAnyPEL, obmcLogIDs);
601 }
602
603 if (!obmcLogIDs.empty())
604 {
605 std::string msg = "Number of PELs removed to save space: " +
606 std::to_string(obmcLogIDs.size());
607 log<level::INFO>(msg.c_str());
608 }
609
610 return obmcLogIDs;
611}
612
613void Repository::removePELs(IsOverLimitFunc& isOverLimit,
614 IsPELTypeFunc& isPELType,
615 std::vector<uint32_t>& removedBMCLogIDs)
616{
617 if (!isOverLimit())
618 {
619 return;
620 }
621
622 auto attributes = getAllPELAttributes(SortOrder::ascending);
623
624 // Make 4 passes on the PELs, stopping as soon as isOverLimit
625 // returns false.
626 // Pass 1: only delete HMC acked PELs
627 // Pass 2: only delete OS acked PELs
628 // Pass 3: only delete PHYP sent PELs
629 // Pass 4: delete all PELs
630 static const std::vector<std::function<bool(const PELAttributes& pel)>>
631 stateChecks{[](const auto& pel) {
632 return pel.hmcState == TransmissionState::acked;
633 },
634
635 [](const auto& pel) {
636 return pel.hostState == TransmissionState::acked;
637 },
638
639 [](const auto& pel) {
640 return pel.hostState == TransmissionState::sent;
641 },
642
643 [](const auto& pel) { return true; }};
644
645 for (const auto& stateCheck : stateChecks)
646 {
647 for (auto it = attributes.begin(); it != attributes.end();)
648 {
649 const auto& pel = it->get();
650 if (isPELType(pel.second) && stateCheck(pel.second))
651 {
652 auto removedID = pel.first.obmcID.id;
653 remove(pel.first);
654
655 removedBMCLogIDs.push_back(removedID);
656
657 attributes.erase(it);
658
659 if (!isOverLimit())
660 {
661 break;
662 }
663 }
664 else
665 {
666 ++it;
667 }
668 }
669
670 if (!isOverLimit())
671 {
672 break;
673 }
674 }
675}
676
Matt Spinler89fa0822019-07-17 13:54:30 -0500677} // namespace pels
678} // namespace openpower