Skip to content

Commit b5652a4

Browse files
authored
Merge pull request #14483 from LDong-Arm/tdbstore_whitebox_low_ram
Improve HeapBlockDevice, TDBStore and tests
2 parents a3be10c + 7b763be commit b5652a4

File tree

6 files changed

+81
-55
lines changed

6 files changed

+81
-55
lines changed

storage/blockdevice/include/blockdevice/HeapBlockDevice.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828

2929
namespace mbed {
3030

31-
/** Lazily allocated heap-backed block device
31+
/** Lazily allocated heap-backed block device.
3232
*
33-
* Useful for simulating a block device and tests
33+
* Useful for simulating a block device and tests.
34+
*
35+
* @note Each block is allocated when used, and freed when erased.
3436
*
3537
* @code
3638
* #include "mbed.h"

storage/blockdevice/source/HeapBlockDevice.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ HeapBlockDevice::~HeapBlockDevice()
4040
{
4141
if (_blocks) {
4242
for (size_t i = 0; i < _count; i++) {
43-
free(_blocks[i]);
43+
delete[] _blocks[i];
4444
}
4545

4646
delete[] _blocks;
47-
_blocks = 0;
47+
_blocks = nullptr;
4848
}
4949
}
5050

@@ -57,9 +57,13 @@ int HeapBlockDevice::init()
5757
}
5858

5959
if (!_blocks) {
60-
_blocks = new uint8_t *[_count];
60+
_blocks = new (std::nothrow) uint8_t *[_count];
61+
if (!_blocks) {
62+
return BD_ERROR_DEVICE_ERROR;
63+
}
64+
6165
for (size_t i = 0; i < _count; i++) {
62-
_blocks[i] = 0;
66+
_blocks[i] = nullptr;
6367
}
6468
}
6569

@@ -156,7 +160,7 @@ int HeapBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
156160
bd_addr_t lo = addr % _erase_size;
157161

158162
if (!_blocks[hi]) {
159-
_blocks[hi] = (uint8_t *)malloc(_erase_size);
163+
_blocks[hi] = new (std::nothrow) uint8_t[_erase_size];
160164
if (!_blocks[hi]) {
161165
return BD_ERROR_DEVICE_ERROR;
162166
}
@@ -180,6 +184,13 @@ int HeapBlockDevice::erase(bd_addr_t addr, bd_size_t size)
180184
if (!is_valid_erase(addr, size)) {
181185
return BD_ERROR_DEVICE_ERROR;
182186
}
187+
188+
for (size_t i = 0; i < (size / _erase_size); i++) {
189+
size_t index = addr / _erase_size + i;
190+
delete[] _blocks[index];
191+
_blocks[index] = nullptr;
192+
}
193+
183194
return 0;
184195
}
185196

storage/kvstore/filesystemstore/tests/UNITTESTS/FileSystemStore/moduletest.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,6 @@ TEST_F(FileSystemStoreModuleTest, set_get)
6767
EXPECT_STREQ("data", buf);
6868
}
6969

70-
TEST_F(FileSystemStoreModuleTest, erased_set_get)
71-
{
72-
EXPECT_EQ(store->deinit(), MBED_SUCCESS);
73-
EXPECT_EQ(heap.init(), MBED_SUCCESS);
74-
EXPECT_EQ(heap.erase(0, heap.size()), MBED_SUCCESS);
75-
EXPECT_EQ(heap.deinit(), MBED_SUCCESS);
76-
EXPECT_EQ(store->init(), MBED_SUCCESS);
77-
char buf[100];
78-
size_t size;
79-
EXPECT_EQ(store->set("key", "data", 5, 0), MBED_SUCCESS);
80-
EXPECT_EQ(store->get("key", buf, 100, &size), MBED_SUCCESS);
81-
EXPECT_EQ(size, 5);
82-
EXPECT_STREQ("data", buf);
83-
}
84-
8570
TEST_F(FileSystemStoreModuleTest, set_deinit_init_get)
8671
{
8772
char buf[100];

storage/kvstore/tdbstore/include/tdbstore/TDBStore.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,14 +346,15 @@ class TDBStore : public KVStore {
346346
int reset_area(uint8_t area);
347347

348348
/**
349-
* @brief Erase an erase unit.
349+
* @brief Erase an area.
350350
*
351351
* @param[in] area Area.
352352
* @param[in] offset Offset in area.
353+
* @param[in] size Number of bytes to erase.
353354
*
354355
* @returns 0 for success, nonzero for failure.
355356
*/
356-
int erase_erase_unit(uint8_t area, uint32_t offset);
357+
int erase_area(uint8_t area, uint32_t offset, uint32_t size);
357358

358359
/**
359360
* @brief Calculate addresses and sizes of areas.

storage/kvstore/tdbstore/source/TDBStore.cpp

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -170,24 +170,31 @@ int TDBStore::write_area(uint8_t area, uint32_t offset, uint32_t size, const voi
170170
return MBED_SUCCESS;
171171
}
172172

173-
int TDBStore::erase_erase_unit(uint8_t area, uint32_t offset)
173+
int TDBStore::erase_area(uint8_t area, uint32_t offset, uint32_t size)
174174
{
175175
uint32_t bd_offset = _area_params[area].address + offset;
176-
uint32_t eu_size = _buff_bd->get_erase_size(bd_offset);
177176

178-
if (_buff_bd->get_erase_value() != -1) {
179-
return _buff_bd->erase(bd_offset, eu_size);
180-
} else {
181-
// We need to simulate erase, as our block device
182-
// does not do it. We can do this one byte at a time
183-
// because we use BufferedBlockDevice that has page buffers
184-
uint8_t val = 0xff;
185-
int ret;
186-
for (; eu_size; --eu_size) {
187-
ret = _buff_bd->program(&val, bd_offset++, 1);
177+
int ret = _buff_bd->erase(bd_offset, size);
178+
if (ret) {
179+
return ret;
180+
}
181+
182+
if (_buff_bd->get_erase_value() == -1) {
183+
// We need to simulate erase to wipe records, as our block device
184+
// may not do it. Program in chunks of _work_buf_size if the minimum
185+
// program size is too small (e.g. one-byte) to avoid performance
186+
// issues.
187+
MBED_ASSERT(_work_buf != nullptr);
188+
MBED_ASSERT(_work_buf_size != 0);
189+
memset(_work_buf, 0xFF, _work_buf_size);
190+
while (size) {
191+
uint32_t chunk = std::min<uint32_t>(_work_buf_size, size);
192+
ret = _buff_bd->program(_work_buf, bd_offset, chunk);
188193
if (ret) {
189194
return ret;
190195
}
196+
size -= chunk;
197+
bd_offset += chunk;
191198
}
192199
}
193200
return MBED_SUCCESS;
@@ -1458,33 +1465,47 @@ void TDBStore::offset_in_erase_unit(uint8_t area, uint32_t offset,
14581465
uint32_t &offset_from_start, uint32_t &dist_to_end)
14591466
{
14601467
uint32_t bd_offset = _area_params[area].address + offset;
1461-
uint32_t agg_offset = 0;
14621468

1463-
while (bd_offset >= agg_offset + _buff_bd->get_erase_size(agg_offset)) {
1464-
agg_offset += _buff_bd->get_erase_size(agg_offset);
1465-
}
1466-
offset_from_start = bd_offset - agg_offset;
1467-
dist_to_end = _buff_bd->get_erase_size(agg_offset) - offset_from_start;
1469+
// The parameter of `BlockDevice::get_erase_size(bd_addr_t addr)`
1470+
// does not need to be aligned.
1471+
uint32_t erase_unit = _buff_bd->get_erase_size(bd_offset);
1472+
1473+
// Even on a flash device with multiple regions, the start address of
1474+
// an erase unit is aligned to the current region's unit size.
1475+
offset_from_start = bd_offset % erase_unit;
1476+
dist_to_end = erase_unit - offset_from_start;
14681477
}
14691478

14701479
int TDBStore::check_erase_before_write(uint8_t area, uint32_t offset, uint32_t size, bool force_check)
14711480
{
14721481
// In order to save init time, we don't check that the entire area is erased.
14731482
// Instead, whenever reaching an erase unit start erase it.
1483+
bool erase = false;
1484+
uint32_t start_offset;
1485+
uint32_t end_offset;
14741486
while (size) {
14751487
uint32_t dist, offset_from_start;
14761488
int ret;
14771489
offset_in_erase_unit(area, offset, offset_from_start, dist);
14781490
uint32_t chunk = std::min(size, dist);
14791491

14801492
if (offset_from_start == 0 || force_check) {
1481-
ret = erase_erase_unit(area, offset - offset_from_start);
1482-
if (ret != MBED_SUCCESS) {
1483-
return MBED_ERROR_WRITE_FAILED;
1493+
if (!erase) {
1494+
erase = true;
1495+
start_offset = offset - offset_from_start;
14841496
}
1497+
end_offset = offset + dist;
14851498
}
14861499
offset += chunk;
14871500
size -= chunk;
14881501
}
1502+
1503+
if (erase) {
1504+
int ret = erase_area(area, start_offset, end_offset - start_offset);
1505+
if (ret != MBED_SUCCESS) {
1506+
return MBED_ERROR_WRITE_FAILED;
1507+
}
1508+
}
1509+
14891510
return MBED_SUCCESS;
14901511
}

storage/kvstore/tdbstore/tests/TESTS/tdbstore/whitebox/main.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,14 @@ static void white_box_test()
132132
} else {
133133
test_bd = &heap_bd;
134134
// We need to skip the test if we don't have enough memory for the heap block device.
135-
// However, this device allocates the erase units on the fly, so "erase" it via the flash
136-
// simulator. A failure here means we haven't got enough memory.
137-
heap_bd.init();
138-
result = heap_bd.erase(0, heap_bd.size());
139-
TEST_SKIP_UNLESS_MESSAGE(!result, "Not enough heap to run test");
135+
// However, this device allocates the blocks on the fly when programmed. A failure
136+
// here means we haven't got enough memory.
137+
result = heap_bd.init();
138+
TEST_SKIP_UNLESS_MESSAGE(result == BD_ERROR_OK, "Not enough heap to run test")
139+
for (bd_addr_t addr = 0; addr < heap_bd.size(); addr += heap_bd.get_program_size()) {
140+
result = heap_bd.program(dummy, addr, heap_bd.get_program_size());
141+
TEST_SKIP_UNLESS_MESSAGE(result == BD_ERROR_OK, "Not enough heap to run test")
142+
}
140143
heap_bd.deinit();
141144
}
142145

@@ -345,11 +348,14 @@ static void multi_set_test()
345348

346349
#ifdef USE_HEAP_BD
347350
// We need to skip the test if we don't have enough memory for the heap block device.
348-
// However, this device allocates the erase units on the fly, so "erase" it via the flash
349-
// simulator. A failure here means we haven't got enough memory.
350-
flash_bd.init();
351-
result = flash_bd.erase(0, flash_bd.size());
352-
TEST_SKIP_UNLESS_MESSAGE(!result, "Not enough heap to run test");
351+
// However, this device allocates the blocks on the fly when programmed. A failure
352+
// here means we haven't got enough memory.
353+
result = flash_bd.init();
354+
TEST_SKIP_UNLESS_MESSAGE(result == BD_ERROR_OK, "Not enough heap to run test")
355+
for (bd_addr_t addr = 0; addr < flash_bd.size(); addr += flash_bd.get_program_size()) {
356+
result = flash_bd.program(dummy, addr, flash_bd.get_program_size());
357+
TEST_SKIP_UNLESS_MESSAGE(result == BD_ERROR_OK, "Not enough heap to run test")
358+
}
353359
flash_bd.deinit();
354360
#endif
355361

0 commit comments

Comments
 (0)