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