xref: /openbmc/phosphor-logging/extensions/openpower-pels/repository.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "repository.hpp"
5 
6 #include "pel_values.hpp"
7 
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 
11 #include <phosphor-logging/lg2.hpp>
12 #include <xyz/openbmc_project/Common/File/error.hpp>
13 
14 #include <fstream>
15 
16 namespace openpower
17 {
18 namespace pels
19 {
20 
21 namespace fs = std::filesystem;
22 namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error;
23 
24 constexpr size_t warningPercentage = 95;
25 
26 /**
27  * @brief Returns the amount of space the file uses on disk.
28  *
29  * This is different than just the regular size of the file.
30  *
31  * @param[in] file - The file to get the size of
32  *
33  * @return size_t The disk space the file uses
34  */
getFileDiskSize(const std::filesystem::path & file)35 size_t getFileDiskSize(const std::filesystem::path& file)
36 {
37     constexpr size_t statBlockSize = 512;
38     struct stat statData;
39     auto rc = stat(file.c_str(), &statData);
40     if (rc != 0)
41     {
42         auto e = errno;
43         lg2::error("Call to stat() failed on {FILE} with errno {ERRNO}", "FILE",
44                    file.native(), "ERRNO", e);
45         abort();
46     }
47 
48     return statData.st_blocks * statBlockSize;
49 }
50 
Repository(const std::filesystem::path & basePath,size_t repoSize,size_t maxNumPELs)51 Repository::Repository(const std::filesystem::path& basePath, size_t repoSize,
52                        size_t maxNumPELs) :
53     _logPath(basePath / "logs"), _maxRepoSize(repoSize),
54     _maxNumPELs(maxNumPELs), _archivePath(basePath / "logs" / "archive")
55 {
56     if (!fs::exists(_logPath))
57     {
58         fs::create_directories(_logPath);
59     }
60 
61     if (!fs::exists(_archivePath))
62     {
63         fs::create_directories(_archivePath);
64     }
65 
66     restore();
67 }
68 
restore()69 void Repository::restore()
70 {
71     for (auto& dirEntry : fs::directory_iterator(_logPath))
72     {
73         try
74         {
75             if (!fs::is_regular_file(dirEntry.path()))
76             {
77                 continue;
78             }
79 
80             std::ifstream file{dirEntry.path()};
81             std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
82                                       std::istreambuf_iterator<char>()};
83             file.close();
84 
85             PEL pel{data};
86             if (pel.valid())
87             {
88                 // If the host hasn't acked it, reset the host state so
89                 // it will get sent up again.
90                 if (pel.hostTransmissionState() == TransmissionState::sent)
91                 {
92                     pel.setHostTransmissionState(TransmissionState::newPEL);
93                     try
94                     {
95                         write(pel, dirEntry.path());
96                     }
97                     catch (const std::exception& e)
98                     {
99                         lg2::error(
100                             "Failed to save PEL after updating host state, PEL ID = {ID}",
101                             "ID", lg2::hex, pel.id());
102                     }
103                 }
104 
105                 PELAttributes attributes{
106                     dirEntry.path(),
107                     getFileDiskSize(dirEntry.path()),
108                     pel.privateHeader().creatorID(),
109                     pel.userHeader().subsystem(),
110                     pel.userHeader().severity(),
111                     pel.userHeader().actionFlags(),
112                     pel.hostTransmissionState(),
113                     pel.hmcTransmissionState(),
114                     pel.plid(),
115                     pel.getDeconfigFlag(),
116                     pel.getGuardFlag(),
117                     getMillisecondsSinceEpoch(
118                         pel.privateHeader().createTimestamp())};
119 
120                 using pelID = LogID::Pel;
121                 using obmcID = LogID::Obmc;
122                 _pelAttributes.emplace(
123                     LogID(pelID(pel.id()), obmcID(pel.obmcLogID())),
124                     attributes);
125 
126                 updateRepoStats(attributes, true);
127             }
128             else
129             {
130                 lg2::error(
131                     "Found invalid PEL file {FILE} while restoring.  Removing.",
132                     "FILE", dirEntry.path());
133                 fs::remove(dirEntry.path());
134             }
135         }
136         catch (const std::exception& e)
137         {
138             lg2::error("Hit exception while restoring PEL file {FILE}: {ERROR}",
139                        "FILE", dirEntry.path(), "ERROR", e);
140         }
141     }
142 
143     // Get size of archive folder
144     for (auto& dirEntry : fs::directory_iterator(_archivePath))
145     {
146         _archiveSize += getFileDiskSize(dirEntry);
147     }
148 }
149 
getPELFilename(uint32_t pelID,const BCDTime & time)150 std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time)
151 {
152     char name[50];
153     sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", time.yearMSB,
154             time.yearLSB, time.month, time.day, time.hour, time.minutes,
155             time.seconds, time.hundredths, pelID);
156     return std::string{name};
157 }
158 
add(std::unique_ptr<PEL> & pel)159 void Repository::add(std::unique_ptr<PEL>& pel)
160 {
161     pel->setHostTransmissionState(TransmissionState::newPEL);
162     pel->setHMCTransmissionState(TransmissionState::newPEL);
163 
164     auto path = _logPath / getPELFilename(pel->id(), pel->commitTime());
165 
166     write(*(pel.get()), path);
167 
168     PELAttributes attributes{
169         path,
170         getFileDiskSize(path),
171         pel->privateHeader().creatorID(),
172         pel->userHeader().subsystem(),
173         pel->userHeader().severity(),
174         pel->userHeader().actionFlags(),
175         pel->hostTransmissionState(),
176         pel->hmcTransmissionState(),
177         pel->plid(),
178         pel->getDeconfigFlag(),
179         pel->getGuardFlag(),
180         getMillisecondsSinceEpoch(pel->privateHeader().createTimestamp())};
181 
182     using pelID = LogID::Pel;
183     using obmcID = LogID::Obmc;
184     _pelAttributes.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())),
185                            attributes);
186 
187     _lastPelID = pel->id();
188 
189     updateRepoStats(attributes, true);
190 
191     processAddCallbacks(*pel);
192 }
193 
write(const PEL & pel,const fs::path & path)194 void Repository::write(const PEL& pel, const fs::path& path)
195 {
196     std::ofstream file{path, std::ios::binary};
197 
198     if (!file.good())
199     {
200         // If this fails, the filesystem is probably full so it isn't like
201         // we could successfully create yet another error log here.
202         auto e = errno;
203         fs::remove(path);
204         lg2::error(
205             "Unable to open PEL file {FILE} for writing, errno = {ERRNO}",
206             "FILE", path, "ERRNO", e);
207         throw file_error::Open();
208     }
209 
210     auto data = pel.data();
211     file.write(reinterpret_cast<const char*>(data.data()), data.size());
212 
213     if (file.fail())
214     {
215         // Same note as above about not being able to create an error log
216         // for this case even if we wanted.
217         auto e = errno;
218         file.close();
219         fs::remove(path);
220         lg2::error("Unable to write PEL file {FILE}, errno = {ERRNO}", "FILE",
221                    path, "ERRNO", e);
222         throw file_error::Write();
223     }
224 }
225 
remove(const LogID & id)226 std::optional<Repository::LogID> Repository::remove(const LogID& id)
227 {
228     auto pel = findPEL(id);
229     if (pel == _pelAttributes.end())
230     {
231         return std::nullopt;
232     }
233 
234     LogID actualID = pel->first;
235     updateRepoStats(pel->second, false);
236 
237     lg2::debug(
238         "Removing PEL from repository, PEL ID = {PEL_ID}, BMC log ID = {BMC_ID}",
239         "PEL_ID", lg2::hex, actualID.pelID.id, "BMC_ID", actualID.obmcID.id);
240 
241     if (fs::exists(pel->second.path))
242     {
243         // Check for existense of new archive folder
244         if (!fs::exists(_archivePath))
245         {
246             fs::create_directories(_archivePath);
247         }
248 
249         // Move log file to archive folder
250         auto fileName = _archivePath / pel->second.path.filename();
251         fs::rename(pel->second.path, fileName);
252 
253         // Update size of file
254         _archiveSize += getFileDiskSize(fileName);
255     }
256 
257     _pelAttributes.erase(pel);
258 
259     processDeleteCallbacks(actualID.pelID.id);
260 
261     return actualID;
262 }
263 
getPELData(const LogID & id)264 std::optional<std::vector<uint8_t>> Repository::getPELData(const LogID& id)
265 {
266     auto pel = findPEL(id);
267     if (pel != _pelAttributes.end())
268     {
269         std::ifstream file{pel->second.path.c_str()};
270         if (!file.good())
271         {
272             auto e = errno;
273             lg2::error("Unable to open PEL file {FILE}, errno = {ERRNO}",
274                        "FILE", pel->second.path, "ERRNO", e);
275             throw file_error::Open();
276         }
277 
278         std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
279                                   std::istreambuf_iterator<char>()};
280         return data;
281     }
282 
283     return std::nullopt;
284 }
285 
getPELFD(const LogID & id)286 std::optional<sdbusplus::message::unix_fd> Repository::getPELFD(const LogID& id)
287 {
288     auto pel = findPEL(id);
289     if (pel != _pelAttributes.end())
290     {
291         int fd = open(pel->second.path.c_str(), O_RDONLY | O_NONBLOCK);
292         if (fd == -1)
293         {
294             auto e = errno;
295             lg2::error("Unable to open PEL file {FILE}, errno = {ERRNO}",
296                        "FILE", pel->second.path, "ERRNO", e);
297             throw file_error::Open();
298         }
299 
300         // Must leave the file open here.  It will be closed by sdbusplus
301         // when it sends it back over D-Bus.
302         return fd;
303     }
304     return std::nullopt;
305 }
306 
for_each(ForEachFunc func) const307 void Repository::for_each(ForEachFunc func) const
308 {
309     for (const auto& [id, attributes] : _pelAttributes)
310     {
311         std::ifstream file{attributes.path};
312 
313         if (!file.good())
314         {
315             auto e = errno;
316             lg2::error(
317                 "Repository::for_each: Unable to open PEL file {FILE}, errno = {ERRNO}",
318                 "FILE", attributes.path, "ERRNO", e);
319             continue;
320         }
321 
322         std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
323                                   std::istreambuf_iterator<char>()};
324         file.close();
325 
326         PEL pel{data};
327 
328         try
329         {
330             if (func(pel))
331             {
332                 break;
333             }
334         }
335         catch (const std::exception& e)
336         {
337             lg2::error("Repository::for_each function exception: {ERROR}",
338                        "ERROR", e);
339         }
340     }
341 }
342 
processAddCallbacks(const PEL & pel) const343 void Repository::processAddCallbacks(const PEL& pel) const
344 {
345     for (auto& [name, func] : _addSubscriptions)
346     {
347         try
348         {
349             func(pel);
350         }
351         catch (const std::exception& e)
352         {
353             lg2::error(
354                 "PEL Repository add callback exception. Name = {NAME}, Error = {ERROR}",
355                 "NAME", name, "ERROR", e);
356         }
357     }
358 }
359 
processDeleteCallbacks(uint32_t id) const360 void Repository::processDeleteCallbacks(uint32_t id) const
361 {
362     for (auto& [name, func] : _deleteSubscriptions)
363     {
364         try
365         {
366             func(id);
367         }
368         catch (const std::exception& e)
369         {
370             lg2::error(
371                 "PEL Repository delete callback exception. Name = {NAME}, Error = {ERROR}",
372                 "NAME", name, "ERROR", e);
373         }
374     }
375 }
376 
377 std::optional<std::reference_wrapper<const Repository::PELAttributes>>
getPELAttributes(const LogID & id) const378     Repository::getPELAttributes(const LogID& id) const
379 {
380     auto pel = findPEL(id);
381     if (pel != _pelAttributes.end())
382     {
383         return pel->second;
384     }
385 
386     return std::nullopt;
387 }
388 
setPELHostTransState(uint32_t pelID,TransmissionState state)389 void Repository::setPELHostTransState(uint32_t pelID, TransmissionState state)
390 {
391     LogID id{LogID::Pel{pelID}};
392     auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
393                              [&id](const auto& a) { return a.first == id; });
394 
395     if ((attr != _pelAttributes.end()) && (attr->second.hostState != state))
396     {
397         PELUpdateFunc func = [state](PEL& pel) {
398             pel.setHostTransmissionState(state);
399             return true;
400         };
401 
402         try
403         {
404             updatePEL(attr->second.path, func);
405         }
406         catch (const std::exception& e)
407         {
408             lg2::error(
409                 "Unable to update PEL host transmission state. Path = {PATH}, Error = {ERROR}",
410                 "PATH", attr->second.path, "ERROR", e);
411         }
412     }
413 }
414 
setPELHMCTransState(uint32_t pelID,TransmissionState state)415 void Repository::setPELHMCTransState(uint32_t pelID, TransmissionState state)
416 {
417     LogID id{LogID::Pel{pelID}};
418     auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
419                              [&id](const auto& a) { return a.first == id; });
420 
421     if ((attr != _pelAttributes.end()) && (attr->second.hmcState != state))
422     {
423         PELUpdateFunc func = [state](PEL& pel) {
424             pel.setHMCTransmissionState(state);
425             return true;
426         };
427 
428         try
429         {
430             updatePEL(attr->second.path, func);
431         }
432         catch (const std::exception& e)
433         {
434             lg2::error(
435                 "Unable to update PEL HMC transmission state. Path = {PATH}, Error = {ERROR}",
436                 "PATH", attr->second.path, "ERROR", e);
437         }
438     }
439 }
440 
updatePEL(const fs::path & path,PELUpdateFunc updateFunc)441 bool Repository::updatePEL(const fs::path& path, PELUpdateFunc updateFunc)
442 {
443     std::ifstream file{path};
444     std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
445                               std::istreambuf_iterator<char>()};
446     file.close();
447 
448     PEL pel{data};
449 
450     if (pel.valid())
451     {
452         if (updateFunc(pel))
453         {
454             // Three attribute fields can change post creation from
455             // an updatePEL call:
456             //  - hmcTransmissionState - When HMC acks a PEL
457             //  - hostTransmissionState - When host acks a PEL
458             //  - deconfig flag - Can be cleared for PELs that call out
459             //                    hotplugged FRUs.
460             // Make sure they're up to date.
461             LogID id{LogID::Pel(pel.id())};
462             auto attr =
463                 std::find_if(_pelAttributes.begin(), _pelAttributes.end(),
464                              [&id](const auto& a) { return a.first == id; });
465             if (attr != _pelAttributes.end())
466             {
467                 attr->second.hmcState = pel.hmcTransmissionState();
468                 attr->second.hostState = pel.hostTransmissionState();
469                 attr->second.deconfig = pel.getDeconfigFlag();
470             }
471 
472             write(pel, path);
473             return true;
474         }
475     }
476     else
477     {
478         throw std::runtime_error(
479             "Unable to read a valid PEL when trying to update it");
480     }
481     return false;
482 }
483 
isServiceableSev(const PELAttributes & pel)484 bool Repository::isServiceableSev(const PELAttributes& pel)
485 {
486     auto sevType = static_cast<SeverityType>(pel.severity & 0xF0);
487     auto sevPVEntry =
488         pel_values::findByValue(pel.severity, pel_values::severityValues);
489     std::string sevName = std::get<pel_values::registryNamePos>(*sevPVEntry);
490 
491     bool check1 = (sevType == SeverityType::predictive) ||
492                   (sevType == SeverityType::unrecoverable) ||
493                   (sevType == SeverityType::critical);
494 
495     bool check2 = ((sevType == SeverityType::recovered) ||
496                    (sevName == "symptom_recovered")) &&
497                   !pel.actionFlags.test(hiddenFlagBit);
498 
499     bool check3 = (sevName == "symptom_predictive") ||
500                   (sevName == "symptom_unrecoverable") ||
501                   (sevName == "symptom_critical");
502 
503     return check1 || check2 || check3;
504 }
505 
updateRepoStats(const PELAttributes & pel,bool pelAdded)506 void Repository::updateRepoStats(const PELAttributes& pel, bool pelAdded)
507 {
508     auto isServiceable = Repository::isServiceableSev(pel);
509     auto bmcPEL = CreatorID::openBMC == static_cast<CreatorID>(pel.creator);
510 
511     auto adjustSize = [pelAdded, &pel](auto& runningSize) {
512         if (pelAdded)
513         {
514             runningSize += pel.sizeOnDisk;
515         }
516         else
517         {
518             runningSize = std::max(static_cast<int64_t>(runningSize) -
519                                        static_cast<int64_t>(pel.sizeOnDisk),
520                                    static_cast<int64_t>(0));
521         }
522     };
523 
524     adjustSize(_sizes.total);
525 
526     if (bmcPEL)
527     {
528         adjustSize(_sizes.bmc);
529         if (isServiceable)
530         {
531             adjustSize(_sizes.bmcServiceable);
532         }
533         else
534         {
535             adjustSize(_sizes.bmcInfo);
536         }
537     }
538     else
539     {
540         adjustSize(_sizes.nonBMC);
541         if (isServiceable)
542         {
543             adjustSize(_sizes.nonBMCServiceable);
544         }
545         else
546         {
547             adjustSize(_sizes.nonBMCInfo);
548         }
549     }
550 }
551 
sizeWarning()552 bool Repository::sizeWarning()
553 {
554     std::error_code ec;
555 
556     if ((_archiveSize > 0) && ((_sizes.total + _archiveSize) >
557                                ((_maxRepoSize * warningPercentage) / 100)))
558     {
559         lg2::info(
560             "Repository::sizeWarning function:Deleting the files in archive");
561 
562         for (const auto& dirEntry : fs::directory_iterator(_archivePath))
563         {
564             fs::remove(dirEntry.path(), ec);
565             if (ec)
566             {
567                 lg2::info("Repository::sizeWarning: Could not delete "
568                           "file {FILE} in PEL archive",
569                           "FILE", dirEntry.path());
570             }
571         }
572 
573         _archiveSize = 0;
574     }
575 
576     return (_sizes.total > (_maxRepoSize * warningPercentage / 100)) ||
577            (_pelAttributes.size() > _maxNumPELs);
578 }
579 
getAllPELAttributes(SortOrder order) const580 std::vector<Repository::AttributesReference> Repository::getAllPELAttributes(
581     SortOrder order) const
582 {
583     std::vector<Repository::AttributesReference> attributes;
584 
585     std::for_each(_pelAttributes.begin(), _pelAttributes.end(),
586                   [&attributes](auto& pelEntry) {
587                       attributes.push_back(pelEntry);
588                   });
589 
590     std::sort(attributes.begin(), attributes.end(),
591               [order](const auto& left, const auto& right) {
592                   if (order == SortOrder::ascending)
593                   {
594                       return left.get().second.path < right.get().second.path;
595                   }
596                   return left.get().second.path > right.get().second.path;
597               });
598 
599     return attributes;
600 }
601 
prune(const std::vector<uint32_t> & idsWithHwIsoEntry)602 std::vector<uint32_t> Repository::prune(
603     const std::vector<uint32_t>& idsWithHwIsoEntry)
604 {
605     std::vector<uint32_t> obmcLogIDs;
606     lg2::info("Pruning PEL repository that takes up {TOTAL} bytes and has "
607               "{NUM_PELS} PELs",
608               "TOTAL", _sizes.total, "NUM_PELS", _pelAttributes.size());
609 
610     // Set up the 5 functions to check if the PEL category
611     // is still over its limits.
612 
613     // BMC informational PELs should only take up 15%
614     IsOverLimitFunc overBMCInfoLimit = [this]() {
615         return _sizes.bmcInfo > _maxRepoSize * 15 / 100;
616     };
617 
618     // BMC non informational PELs should only take up 30%
619     IsOverLimitFunc overBMCNonInfoLimit = [this]() {
620         return _sizes.bmcServiceable > _maxRepoSize * 30 / 100;
621     };
622 
623     // Non BMC informational PELs should only take up 15%
624     IsOverLimitFunc overNonBMCInfoLimit = [this]() {
625         return _sizes.nonBMCInfo > _maxRepoSize * 15 / 100;
626     };
627 
628     // Non BMC non informational PELs should only take up 15%
629     IsOverLimitFunc overNonBMCNonInfoLimit = [this]() {
630         return _sizes.nonBMCServiceable > _maxRepoSize * 30 / 100;
631     };
632 
633     // Bring the total number of PELs down to 80% of the max
634     IsOverLimitFunc tooManyPELsLimit = [this]() {
635         return _pelAttributes.size() > _maxNumPELs * 80 / 100;
636     };
637 
638     // Set up the functions to determine which category a PEL is in.
639     // TODO: Return false in these functions if a PEL caused a guard record.
640 
641     // A BMC informational PEL
642     IsPELTypeFunc isBMCInfo = [](const PELAttributes& pel) {
643         return (CreatorID::openBMC == static_cast<CreatorID>(pel.creator)) &&
644                !Repository::isServiceableSev(pel);
645     };
646 
647     // A BMC non informational PEL
648     IsPELTypeFunc isBMCNonInfo = [](const PELAttributes& pel) {
649         return (CreatorID::openBMC == static_cast<CreatorID>(pel.creator)) &&
650                Repository::isServiceableSev(pel);
651     };
652 
653     // A non BMC informational PEL
654     IsPELTypeFunc isNonBMCInfo = [](const PELAttributes& pel) {
655         return (CreatorID::openBMC != static_cast<CreatorID>(pel.creator)) &&
656                !Repository::isServiceableSev(pel);
657     };
658 
659     // A non BMC non informational PEL
660     IsPELTypeFunc isNonBMCNonInfo = [](const PELAttributes& pel) {
661         return (CreatorID::openBMC != static_cast<CreatorID>(pel.creator)) &&
662                Repository::isServiceableSev(pel);
663     };
664 
665     // When counting PELs, count every PEL
666     IsPELTypeFunc isAnyPEL = [](const PELAttributes& /*pel*/) { return true; };
667 
668     // Check all 4 categories, which will result in at most 90%
669     // usage (15 + 30 + 15 + 30).
670     removePELs(overBMCInfoLimit, isBMCInfo, idsWithHwIsoEntry, obmcLogIDs);
671     removePELs(overBMCNonInfoLimit, isBMCNonInfo, idsWithHwIsoEntry,
672                obmcLogIDs);
673     removePELs(overNonBMCInfoLimit, isNonBMCInfo, idsWithHwIsoEntry,
674                obmcLogIDs);
675     removePELs(overNonBMCNonInfoLimit, isNonBMCNonInfo, idsWithHwIsoEntry,
676                obmcLogIDs);
677 
678     // After the above pruning check if there are still too many PELs,
679     // which can happen depending on PEL sizes.
680     if (_pelAttributes.size() > _maxNumPELs)
681     {
682         removePELs(tooManyPELsLimit, isAnyPEL, idsWithHwIsoEntry, obmcLogIDs);
683     }
684 
685     if (!obmcLogIDs.empty())
686     {
687         lg2::info("Number of PELs removed to save space: {NUM_PELS}",
688                   "NUM_PELS", obmcLogIDs.size());
689     }
690 
691     return obmcLogIDs;
692 }
693 
removePELs(const IsOverLimitFunc & isOverLimit,const IsPELTypeFunc & isPELType,const std::vector<uint32_t> & idsWithHwIsoEntry,std::vector<uint32_t> & removedBMCLogIDs)694 void Repository::removePELs(const IsOverLimitFunc& isOverLimit,
695                             const IsPELTypeFunc& isPELType,
696                             const std::vector<uint32_t>& idsWithHwIsoEntry,
697                             std::vector<uint32_t>& removedBMCLogIDs)
698 {
699     if (!isOverLimit())
700     {
701         return;
702     }
703 
704     auto attributes = getAllPELAttributes(SortOrder::ascending);
705 
706     // Make 4 passes on the PELs, stopping as soon as isOverLimit
707     // returns false.
708     //   Pass 1: only delete HMC acked PELs
709     //   Pass 2: only delete OS acked PELs
710     //   Pass 3: only delete PHYP sent PELs
711     //   Pass 4: delete all PELs
712     static const std::vector<std::function<bool(const PELAttributes& pel)>>
713         stateChecks{[](const auto& pel) {
714                         return pel.hmcState == TransmissionState::acked;
715                     },
716 
717                     [](const auto& pel) {
718                         return pel.hostState == TransmissionState::acked;
719                     },
720 
721                     [](const auto& pel) {
722                         return pel.hostState == TransmissionState::sent;
723                     },
724 
725                     [](const auto& /*pel*/) { return true; }};
726 
727     for (const auto& stateCheck : stateChecks)
728     {
729         for (auto it = attributes.begin(); it != attributes.end();)
730         {
731             const auto& pel = it->get();
732             if (isPELType(pel.second) && stateCheck(pel.second))
733             {
734                 auto removedID = pel.first.obmcID.id;
735 
736                 auto idFound = std::find(idsWithHwIsoEntry.begin(),
737                                          idsWithHwIsoEntry.end(), removedID);
738                 if (idFound != idsWithHwIsoEntry.end())
739                 {
740                     ++it;
741                     continue;
742                 }
743 
744                 remove(pel.first);
745 
746                 removedBMCLogIDs.push_back(removedID);
747 
748                 attributes.erase(it);
749 
750                 if (!isOverLimit())
751                 {
752                     break;
753                 }
754             }
755             else
756             {
757                 ++it;
758             }
759         }
760 
761         if (!isOverLimit())
762         {
763             break;
764         }
765     }
766 }
767 
archivePEL(const PEL & pel)768 void Repository::archivePEL(const PEL& pel)
769 {
770     if (pel.valid())
771     {
772         auto path = _archivePath / getPELFilename(pel.id(), pel.commitTime());
773 
774         write(pel, path);
775 
776         _archiveSize += getFileDiskSize(path);
777     }
778 }
779 
780 } // namespace pels
781 } // namespace openpower
782