1 #include "pattern.hpp" 2 3 #include "erase.hpp" 4 5 #include <unistd.h> 6 7 #include <phosphor-logging/lg2.hpp> 8 #include <stdplus/fd/create.hpp> 9 #include <stdplus/fd/managed.hpp> 10 #include <xyz/openbmc_project/Common/error.hpp> 11 12 #include <array> 13 #include <chrono> 14 #include <iostream> 15 #include <random> 16 #include <span> 17 #include <string> 18 #include <thread> 19 20 namespace estoraged 21 { 22 23 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 24 using stdplus::fd::Fd; 25 26 void Pattern::writePattern(const uint64_t driveSize, Fd& fd) 27 { 28 // static seed defines a fixed prng sequnce so it can be verified later, 29 // and validated for entropy 30 uint64_t currentIndex = 0; 31 32 // random number generator seeded with a constant value will 33 // generate a predictable sequence of values NOLINTNEXTLINE 34 std::minstd_rand0 generator(seed); 35 std::array<std::byte, blockSize> randArr{}; 36 37 while (currentIndex < driveSize) 38 { 39 // generate a 4k block of prng 40 std::array<uint32_t, blockSizeUsing32>* randArrFill = 41 reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>(&randArr); 42 for (uint32_t i = 0; i < blockSizeUsing32; i++) 43 { 44 (*randArrFill)[i] = generator(); 45 } 46 // if we can write all 4k bytes do that, else write the remainder 47 size_t writeSize = currentIndex + blockSize < driveSize 48 ? blockSize 49 : driveSize - currentIndex; 50 size_t written = 0; 51 size_t retry = 0; 52 while (written < writeSize) 53 { 54 written += fd.write({randArr.data() + written, writeSize - written}) 55 .size(); 56 if (written == writeSize) 57 { 58 break; 59 } 60 if (written > writeSize) 61 { 62 throw InternalFailure(); 63 } 64 retry++; 65 if (retry > maxRetry) 66 { 67 lg2::error("Unable to do full write", "REDFISH_MESSAGE_ID", 68 std::string("eStorageD.1.0.EraseFailure")); 69 throw InternalFailure(); 70 } 71 std::this_thread::sleep_for(delay); 72 } 73 currentIndex = currentIndex + writeSize; 74 } 75 } 76 77 void Pattern::verifyPattern(const uint64_t driveSize, Fd& fd) 78 { 79 uint64_t currentIndex = 0; 80 // random number generator seeded with a constant value will 81 // generate a predictable sequence of values NOLINTNEXTLINE 82 std::minstd_rand0 generator(seed); 83 std::array<std::byte, blockSize> randArr{}; 84 std::array<std::byte, blockSize> readArr{}; 85 86 while (currentIndex < driveSize) 87 { 88 size_t readSize = currentIndex + blockSize < driveSize 89 ? blockSize 90 : driveSize - currentIndex; 91 try 92 { 93 std::array<uint32_t, blockSizeUsing32>* randArrFill = 94 reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>( 95 &randArr); 96 for (uint32_t i = 0; i < blockSizeUsing32; i++) 97 { 98 (*randArrFill)[i] = generator(); 99 } 100 size_t read = 0; 101 size_t retry = 0; 102 while (read < readSize) 103 { 104 read += 105 fd.read({readArr.data() + read, readSize - read}).size(); 106 if (read == readSize) 107 { 108 break; 109 } 110 if (read > readSize) 111 { 112 throw InternalFailure(); 113 } 114 retry++; 115 if (retry > maxRetry) 116 { 117 lg2::error("Unable to do full read", "REDFISH_MESSAGE_ID", 118 std::string("eStorageD.1.0.EraseFailure")); 119 throw InternalFailure(); 120 } 121 std::this_thread::sleep_for(delay); 122 } 123 } 124 catch (...) 125 { 126 lg2::error("Estoraged erase pattern unable to read", 127 "REDFISH_MESSAGE_ID", 128 std::string("eStorageD.1.0.EraseFailure")); 129 throw InternalFailure(); 130 } 131 132 if (!std::equal(randArr.begin(), randArr.begin() + readSize, 133 readArr.begin(), readArr.begin() + readSize)) 134 { 135 lg2::error("Estoraged erase pattern does not match", 136 "REDFISH_MESSAGE_ID", 137 std::string("eStorageD.1.0.EraseFailure")); 138 throw InternalFailure(); 139 } 140 currentIndex = currentIndex + readSize; 141 } 142 } 143 144 } // namespace estoraged 145