Coverage Report

Created: 2026-07-16 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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