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 80 uint64_t currentIndex = 0; 81 // random number generator seeded with a constant value will 82 // generate a predictable sequence of values NOLINTNEXTLINE 83 std::minstd_rand0 generator(seed); 84 std::array<std::byte, blockSize> randArr{}; 85 std::array<std::byte, blockSize> readArr{}; 86 87 while (currentIndex < driveSize) 88 { 89 size_t readSize = currentIndex + blockSize < driveSize 90 ? blockSize 91 : driveSize - currentIndex; 92 try 93 { 94 std::array<uint32_t, blockSizeUsing32>* randArrFill = 95 reinterpret_cast<std::array<uint32_t, blockSizeUsing32>*>( 96 &randArr); 97 for (uint32_t i = 0; i < blockSizeUsing32; i++) 98 { 99 (*randArrFill)[i] = generator(); 100 } 101 size_t read = 0; 102 size_t retry = 0; 103 while (read < readSize) 104 { 105 read += 106 fd.read({readArr.data() + read, readSize - read}).size(); 107 if (read == readSize) 108 { 109 break; 110 } 111 if (read > readSize) 112 { 113 throw InternalFailure(); 114 } 115 retry++; 116 if (retry > maxRetry) 117 { 118 lg2::error("Unable to do full read", "REDFISH_MESSAGE_ID", 119 std::string("eStorageD.1.0.EraseFailure")); 120 throw InternalFailure(); 121 } 122 std::this_thread::sleep_for(delay); 123 } 124 } 125 catch (...) 126 { 127 lg2::error("Estoraged erase pattern unable to read", 128 "REDFISH_MESSAGE_ID", 129 std::string("eStorageD.1.0.EraseFailure")); 130 throw InternalFailure(); 131 } 132 133 if (!std::equal(randArr.begin(), randArr.begin() + readSize, 134 readArr.begin(), readArr.begin() + readSize)) 135 { 136 lg2::error("Estoraged erase pattern does not match", 137 "REDFISH_MESSAGE_ID", 138 std::string("eStorageD.1.0.EraseFailure")); 139 throw InternalFailure(); 140 } 141 currentIndex = currentIndex + readSize; 142 } 143 } 144 145 } // namespace estoraged 146