xref: /openbmc/estoraged/src/erase/pattern.cpp (revision d4554f2a)
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 
writePattern(const uint64_t driveSize,Fd & fd)26 void Pattern::writePattern(const uint64_t driveSize, Fd& fd)
27 {
28     // static seed defines a fixed prng sequence 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 
verifyPattern(const uint64_t driveSize,Fd & fd)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