Skip to content

Commit e89b93c

Browse files
author
Seppo Takalo
committed
TDBStore safety check: Erase if there is valid keys on the free space.
In case our are contains data from previous reset() or reset_area(), we might end up in the situation where free space contains valid key headers, but we have not erased that area yet. This can cause failures if the deinit() and init() because new scan of that area would continue as long as keys are found. This causes keys on the not-yet-erased area to be included in the new instance of TDBStore. To prevent this failure, check after each key-write that our free space does not contain valid key headers. Also make sure that we erase one program unit sector over the master record. If we erased just the master record,first key might is still there, causing next init() to find it. Extend erase area by one program unit, so that build_ram_table() won't find any keys.
1 parent 8bedb63 commit e89b93c

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ TEST_F(TDBStoreModuleTest, reset)
7272
size_t size, read;
7373
// Write so much, that we are sure that garbage collection have kicked up
7474
for (int i = 0; i < 100; ++i) {
75-
size = sprintf(buf, "data%d", i);
75+
size = sprintf(buf, "reset_%d", i);
7676
EXPECT_EQ(tdb.set("key", buf, size, 0), MBED_SUCCESS);
7777
}
7878
EXPECT_EQ(tdb.reset(), MBED_SUCCESS);
@@ -82,6 +82,17 @@ TEST_F(TDBStoreModuleTest, reset)
8282
EXPECT_NE(tdb.get("key", buf, 100, &read), MBED_SUCCESS);
8383
}
8484

85+
TEST_F(TDBStoreModuleTest, remove)
86+
{
87+
char buf[100];
88+
size_t size;
89+
EXPECT_EQ(tdb.set("key", "data1", 5, 0), MBED_SUCCESS);
90+
EXPECT_EQ(tdb.set("key", "data2", 5, 0), MBED_SUCCESS);
91+
EXPECT_EQ(tdb.remove("key"), MBED_SUCCESS);
92+
// Previous key should not be found
93+
EXPECT_NE(tdb.get("key", buf, 100, &size), MBED_SUCCESS);
94+
}
95+
8596
TEST_F(TDBStoreModuleTest, set_deinit_init_get)
8697
{
8798
char buf[100];

features/storage/kvstore/tdbstore/TDBStore.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ TDBStore::~TDBStore()
149149

150150
int TDBStore::read_area(uint8_t area, uint32_t offset, uint32_t size, void *buf)
151151
{
152+
//Check that we are not crossing area boundary
153+
if (offset + size > _size) {
154+
return MBED_ERROR_READ_FAILED;
155+
}
152156
int os_ret = _buff_bd->read(buf, _area_params[area].address + offset, size);
153157

154158
if (os_ret) {
@@ -650,6 +654,15 @@ int TDBStore::set_finalize(set_handle_t handle)
650654

651655
_free_space_offset = align_up(ih->bd_curr_offset, _prog_size);
652656

657+
// Safety check: If there seems to be valid keys on the free space
658+
// we should erase one sector more, just to ensure that in case of power failure
659+
// next init() would not extend the scan phase to that section as well.
660+
os_ret = read_record(_active_area, _free_space_offset, 0, 0, 0, actual_data_size, 0,
661+
false, false, false, false, hash, flags, next_offset);
662+
if (os_ret == MBED_SUCCESS) {
663+
check_erase_before_write(_active_area, _free_space_offset, sizeof(record_header_t));
664+
}
665+
653666
end:
654667
if ((need_gc) && (ih->bd_base_offset != _master_record_offset)) {
655668
garbage_collection();
@@ -946,6 +959,7 @@ int TDBStore::increment_max_keys(void **ram_table)
946959
// Reallocate ram table with new size
947960
ram_table_entry_t *old_ram_table = (ram_table_entry_t *) _ram_table;
948961
ram_table_entry_t *new_ram_table = new ram_table_entry_t[_max_keys + 1];
962+
memset(new_ram_table, 0, sizeof(ram_table_entry_t)*(_max_keys + 1));
949963

950964
// Copy old content to new table
951965
memcpy(new_ram_table, old_ram_table, sizeof(ram_table_entry_t) * _max_keys);
@@ -992,6 +1006,7 @@ int TDBStore::init()
9921006
_max_keys = initial_max_keys;
9931007

9941008
ram_table = new ram_table_entry_t[_max_keys];
1009+
memset(ram_table, 0, sizeof(ram_table_entry_t) * _max_keys);
9951010
_ram_table = ram_table;
9961011
_num_keys = 0;
9971012

@@ -1132,7 +1147,7 @@ int TDBStore::reset_area(uint8_t area)
11321147
bool copy_reserved_data = do_reserved_data_get(buf, sizeof(buf), 0, buf + RESERVED_AREA_SIZE) == MBED_SUCCESS;
11331148

11341149
// Erase reserved area and master record
1135-
ret = check_erase_before_write(area, 0, _master_record_offset + _master_record_size, true);
1150+
ret = check_erase_before_write(area, 0, _master_record_offset + _master_record_size + _prog_size, true);
11361151
if (ret) {
11371152
return ret;
11381153
}
@@ -1155,7 +1170,7 @@ int TDBStore::reset()
11551170

11561171
// Reset both areas
11571172
for (area = 0; area < _num_areas; area++) {
1158-
ret = check_erase_before_write(area, 0, _master_record_offset + _master_record_size, true);
1173+
ret = check_erase_before_write(area, 0, _master_record_offset + _master_record_size + _prog_size, true);
11591174
if (ret) {
11601175
goto end;
11611176
}
@@ -1165,7 +1180,7 @@ int TDBStore::reset()
11651180
_num_keys = 0;
11661181
_free_space_offset = _master_record_offset;
11671182
_active_area_version = 1;
1168-
1183+
memset(_ram_table, 0, sizeof(ram_table_entry_t) * _max_keys);
11691184
// Write an initial master record on active area
11701185
ret = write_master_record(_active_area, _active_area_version, _free_space_offset);
11711186

features/storage/kvstore/tdbstore/TDBStore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ class TDBStore : public KVStore {
368368
*
369369
* @param[in] area Area.
370370
* @param[in] offset Offset of record in area.
371-
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
372-
* @param[in] data_buf Data buffer.
371+
* @param[out] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
372+
* @param[out] data_buf Data buffer.
373373
* @param[in] data_buf_size Data buffer size.
374374
* @param[out] actual_data_size Actual data size.
375375
* @param[in] data_offset Offset in data.

0 commit comments

Comments
 (0)