Merge branch 'bugfix/nvs_close_nukes_all_handles_v4.2' into 'release/v4.2'

NVS: fixed deinit other partition's handles (v4.2)

See merge request espressif/esp-idf!11497
This commit is contained in:
Ivan Grokhotkov 2021-02-05 10:06:37 +08:00
commit 74e1613b17
5 changed files with 122 additions and 18 deletions

View File

@ -19,6 +19,7 @@
#include "nvs_partition_manager.hpp"
#include "esp_partition.h"
#include "sdkconfig.h"
#include <functional>
#include "nvs_handle_simple.hpp"
#ifdef CONFIG_NVS_ENCRYPTION
#include "nvs_encr.hpp"
@ -120,8 +121,16 @@ extern "C" esp_err_t nvs_flash_secure_init_custom(const char *partName, uint32_t
static esp_err_t close_handles_and_deinit(const char* part_name)
{
// Delete all corresponding open handles
s_nvs_handles.clearAndFreeNodes();
auto belongs_to_part = [=](NVSHandleEntry& e) -> bool {
return strncmp(e.nvs_handle->get_partition_name(), part_name, NVS_PART_NAME_MAX_SIZE) == 0;
};
auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), belongs_to_part);
while (it != end(s_nvs_handles)) {
s_nvs_handles.erase(it);
it = find_if(begin(s_nvs_handles), end(s_nvs_handles), belongs_to_part);
}
// Deinit partition
return NVSPartitionManager::get_instance()->deinit_partition(part_name);

View File

@ -130,4 +130,8 @@ bool NVSHandleSimple::nextEntry(nvs_opaque_iterator_t* it) {
return mStoragePtr->nextEntry(it);
}
const char *NVSHandleSimple::get_partition_name() const {
return mStoragePtr->getPartName();
}
}

View File

@ -76,6 +76,8 @@ public:
bool nextEntry(nvs_opaque_iterator_t *it);
const char *get_partition_name() const;
private:
/**
* The underlying storage's object.

View File

@ -533,7 +533,7 @@ TEST_CASE("erase operations are distributed among sectors", "[nvs]")
SpiFlashEmulator emu(sectors);
Storage storage;
CHECK(storage.init(0, sectors) == ESP_OK);
/* Fill some part of storage with static values */
const size_t static_sectors = 2;
for (size_t i = 0; i < static_sectors * Page::ENTRY_COUNT; ++i) {
@ -732,8 +732,9 @@ TEST_CASE("nvs api tests", "[nvs]")
CHECK(0 == strcmp(buf, str));
nvs_close(handle_1);
nvs_close(handle_2);
}
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("nvs iterators tests", "[nvs]")
{
@ -893,6 +894,8 @@ TEST_CASE("nvs iterators tests", "[nvs]")
nvs_close(handle_1);
nvs_close(handle_2);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Iterator with not matching type iterates correctly", "[nvs]")
@ -927,6 +930,8 @@ TEST_CASE("Iterator with not matching type iterates correctly", "[nvs]")
it = nvs_entry_find(NVS_DEFAULT_PART_NAME, NAMESPACE, NVS_TYPE_STR);
CHECK(it != NULL);
nvs_release_iterator(it);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("wifi test", "[nvs]")
@ -934,7 +939,6 @@ TEST_CASE("wifi test", "[nvs]")
SpiFlashEmulator emu(10);
emu.randomize(10);
const uint32_t NVS_FLASH_SECTOR = 5;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
@ -1068,6 +1072,7 @@ TEST_CASE("wifi test", "[nvs]")
s_perf << "Time to simulate nvs init with wifi libs: " << emu.getTotalTime() << " us (" << emu.getEraseOps() << "E " << emu.getWriteOps() << "W " << emu.getReadOps() << "R " << emu.getWriteBytes() << "Wb " << emu.getReadBytes() << "Rb)" << std::endl;
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("writing the identical content does not write or erase", "[nvs]")
@ -1121,6 +1126,8 @@ TEST_CASE("writing the identical content does not write or erase", "[nvs]")
nvs_set_blob(misc_handle, "test_blob", blob, sizeof(blob));
CHECK(emu.getWriteOps() != 0);
CHECK(emu.getReadOps() != 0);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("can init storage from flash with random contents", "[nvs]")
@ -1140,6 +1147,8 @@ TEST_CASE("can init storage from flash with random contents", "[nvs]")
if (nvs_get_u8(handle, "wifi.opmode", &opmode) != ESP_OK) {
TEST_ESP_OK(nvs_set_u8(handle, "wifi.opmode", opmode));
}
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
@ -1194,6 +1203,8 @@ TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][long]")
nvs_close(handle_2);
}
nvs_close(handle_1);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
}
extern "C" void nvs_dump(const char *partName);
@ -1477,6 +1488,8 @@ TEST_CASE("monkey test", "[nvs][monkey]")
CHECK(test.doRandomThings(handle, gen, count) == ESP_OK);
s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl;
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("test recovery from sudden poweroff", "[long][nvs][recovery][monkey]")
@ -1534,6 +1547,8 @@ TEST_CASE("test recovery from sudden poweroff", "[long][nvs][recovery][monkey]")
}
nvs_close(handle);
totalOps = emu.getEraseOps() + emu.getWriteBytes() / 4;
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
}
TEST_CASE("test for memory leaks in open/set", "[leaks]")
@ -1552,6 +1567,8 @@ TEST_CASE("test for memory leaks in open/set", "[leaks]")
TEST_ESP_OK(nvs_commit(light_handle));
nvs_close(light_handle);
}
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("duplicate items are removed", "[nvs][dupes]")
@ -1724,6 +1741,8 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]")
}
nvs_close(light_handle);
}
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
@ -1745,6 +1764,8 @@ TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
// first two pages are now full, third one is writable, last two are empty
// init should fail
TEST_ESP_ERR( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NO_FREE_PAGES );
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("multiple partitions access check", "[nvs]")
@ -1762,6 +1783,9 @@ TEST_CASE("multiple partitions access check", "[nvs]")
TEST_ESP_OK( nvs_get_i32(handle2, "foo", &v2));
CHECK(v1 == 0xdeadbeef);
CHECK(v2 == 0xcafebabe);
TEST_ESP_OK(nvs_flash_deinit_partition("nvs1"));
TEST_ESP_OK(nvs_flash_deinit_partition("nvs2"));
}
TEST_CASE("nvs page selection takes into account free entries also not just erased entries", "[nvs]")
@ -1783,6 +1807,8 @@ TEST_CASE("nvs page selection takes into account free entries also not just eras
TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, 4) );
TEST_ESP_OK( nvs_commit(handle) );
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("calculate used and free space", "[nvs]")
@ -1918,6 +1944,8 @@ TEST_CASE("calculate used and free space", "[nvs]")
CHECK(stat1.used_entries == (h1_count_entries + h2_count_entries + h3_count_entries + stat1.namespace_count));
nvs_close(handle_3);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Recovery from power-off when the entry being erased is not on active page", "[nvs]")
@ -1946,6 +1974,8 @@ TEST_CASE("Recovery from power-off when the entry being erased is not on active
TEST_ESP_OK( nvs_get_blob(handle, "1b", blob, &read_size));
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Recovery from power-off when page is being freed.", "[nvs]")
@ -1987,6 +2017,8 @@ TEST_CASE("Recovery from power-off when page is being freed.", "[nvs]")
TEST_ESP_OK(nvs_commit(handle));
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Multi-page blobs are supported", "[nvs]")
@ -2000,6 +2032,8 @@ TEST_CASE("Multi-page blobs are supported", "[nvs]")
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
TEST_ESP_OK(nvs_commit(handle));
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Failures are handled while storing multi-page blobs", "[nvs]")
@ -2014,6 +2048,8 @@ TEST_CASE("Failures are handled while storing multi-page blobs", "[nvs]")
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, Page::CHUNK_MAX_SIZE*2));
TEST_ESP_OK(nvs_commit(handle));
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Reading multi-page blobs", "[nvs]")
@ -2033,6 +2069,8 @@ TEST_CASE("Reading multi-page blobs", "[nvs]")
CHECK(memcmp(blob, blob_read, blob_size) == 0);
TEST_ESP_OK(nvs_commit(handle));
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Modification of values for Multi-page blobs are supported", "[nvs]")
@ -2061,6 +2099,8 @@ TEST_CASE("Modification of values for Multi-page blobs are supported", "[nvs]")
CHECK(memcmp(blob4, blob_read, blob_size) == 0);
TEST_ESP_OK( nvs_commit(handle) );
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Modification from single page blob to multi-page", "[nvs]")
@ -2079,6 +2119,8 @@ TEST_CASE("Modification from single page blob to multi-page", "[nvs]")
CHECK(memcmp(blob, blob_read, blob_size) == 0);
TEST_ESP_OK(nvs_commit(handle) );
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Modification from multi-page to single page", "[nvs]")
@ -2098,6 +2140,8 @@ TEST_CASE("Modification from multi-page to single page", "[nvs]")
CHECK(memcmp(blob, blob_read, Page::CHUNK_MAX_SIZE) == 0);
TEST_ESP_OK(nvs_commit(handle) );
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Multi-page blob erased using nvs_erase_key should not be found when probed for just length", "[nvs]")
@ -2114,6 +2158,8 @@ TEST_CASE("Multi-page blob erased using nvs_erase_key should not be found when p
TEST_ESP_ERR(nvs_get_blob(handle, "abc", NULL, &read_size), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_commit(handle));
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
@ -2167,6 +2213,8 @@ TEST_CASE("nvs blob fragmentation test", "[nvs]")
TEST_ESP_OK( nvs_set_u32(h, seq_buf, i) );
}
free(blob);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("nvs code handles errors properly when partition is near to full", "[nvs]")
@ -2202,6 +2250,8 @@ TEST_CASE("Check for nvs version incompatibility", "[nvs]")
TEST_ESP_OK(p.writeItem(1, ItemType::I32, "foo", &val1, sizeof(val1)));
TEST_ESP_ERR(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NEW_VERSION_FOUND);
nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME);
}
TEST_CASE("Check that NVS supports old blob format without blob index", "[nvs]")
@ -2247,6 +2297,7 @@ TEST_CASE("Check that NVS supports old blob format without blob index", "[nvs]")
TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen));
CHECK(memcmp(buf, base64data, buflen) == 0);
TEST_ESP_OK(nvs_flash_deinit_partition("test"));
}
TEST_CASE("monkey test with old-format blob present", "[nvs][monkey]")
@ -2337,6 +2388,8 @@ TEST_CASE("monkey test with old-format blob present", "[nvs][monkey]")
}
s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl;
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Recovery from power-off during modification of blob present in old-format (same page)", "[nvs]")
@ -2389,6 +2442,7 @@ TEST_CASE("Recovery from power-off during modification of blob present in old-fo
p2.load(0);
TEST_ESP_ERR(p2.findItem(1, ItemType::BLOB, "singlepage"), ESP_ERR_NVS_TYPE_MISMATCH);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
TEST_CASE("Recovery from power-off during modification of blob present in old-format (different page)", "[nvs]")
@ -2445,6 +2499,8 @@ TEST_CASE("Recovery from power-off during modification of blob present in old-fo
Page p3;
p3.load(0);
TEST_ESP_ERR(p3.findItem(1, ItemType::BLOB, "singlepage"), ESP_ERR_NVS_NOT_FOUND);
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
}
static void check_nvs_part_gen_args(char const *part_name, int size, char const *filename, bool is_encr, nvs_sec_cfg_t* xts_cfg)
@ -2510,6 +2566,8 @@ static void check_nvs_part_gen_args(char const *part_name, int size, char const
file.close();
nvs_close(handle);
TEST_ESP_OK(nvs_flash_deinit_partition(part_name));
}
@ -2550,8 +2608,6 @@ TEST_CASE("check and read data from partition generated via partition generation
SpiFlashEmulator emu("../nvs_partition_generator/partition_single_page.bin");
TEST_ESP_OK(nvs_flash_deinit());
check_nvs_part_gen_args("test", 3, "../nvs_partition_generator/testdata/sample_singlepage_blob.bin", false, NULL);
childpid = fork();
@ -2914,8 +2970,8 @@ TEST_CASE("test nvs apis with encryption enabled", "[nvs]")
CHECK(0 == strcmp(buf, str));
nvs_close(handle_1);
nvs_close(handle_2);
TEST_ESP_OK(nvs_flash_deinit());
TEST_ESP_OK(nvs_flash_deinit());
}
TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled", "[nvs_part_gen]")
@ -3086,7 +3142,6 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena
fclose(fp);
TEST_ESP_OK(nvs_flash_deinit());
nvs_sec_cfg_t cfg;
for(int count = 0; count < NVS_KEY_SIZE; count++) {
@ -3154,7 +3209,6 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena
fclose(fp);
TEST_ESP_OK(nvs_flash_deinit());
nvs_sec_cfg_t cfg;
for(int count = 0; count < NVS_KEY_SIZE; count++) {
@ -3253,8 +3307,6 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit
SpiFlashEmulator emu1("../../../tools/mass_mfg/host_test/bin/Test-1.bin");
TEST_ESP_OK(nvs_flash_deinit());
nvs_sec_cfg_t cfg;
for(int count = 0; count < NVS_KEY_SIZE; count++) {
cfg.eky[count] = 0x11;
@ -3265,8 +3317,6 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit
SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition-encrypted.bin");
TEST_ESP_OK(nvs_flash_deinit());
check_nvs_part_gen_args(NVS_DEFAULT_PART_NAME, 4, "testdata/sample_multipage_blob.bin", true, &cfg);
@ -3376,8 +3426,6 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit
fclose(fp);
TEST_ESP_OK(nvs_flash_deinit());
nvs_sec_cfg_t cfg;
for(int count = 0; count < NVS_KEY_SIZE; count++) {
@ -3389,8 +3437,6 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit
SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition-encrypted.bin");
TEST_ESP_OK(nvs_flash_deinit());
check_nvs_part_gen_args(NVS_DEFAULT_PART_NAME, 4, "testdata/sample_multipage_blob.bin", true, &cfg);
childpid = fork();

View File

@ -20,6 +20,8 @@
using namespace nvs;
#define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)
TEST_CASE("nvs_flash_init_partition_ptr fails due to nullptr arg", "[nvs_custom_part]")
{
const uint32_t NVS_FLASH_SECTOR = 6;
@ -61,4 +63,45 @@ TEST_CASE("nvs_flash_init_partition_ptr inits one partition", "[nvs_custom_part]
CHECK(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
}
TEST_CASE("deinit partition doesn't affect other partition's open handles", "[nvs]")
{
const char *OTHER_PARTITION_NAME = "other_part";
const uint32_t NVS_FLASH_SECTOR = 6;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
SpiFlashEmulator emu_default(10);
emu_default.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
esp_partition_t part_default = {};
strcpy(part_default.label, NVS_DEFAULT_PART_NAME);
part_default.address = NVS_FLASH_SECTOR * SPI_FLASH_SEC_SIZE;
part_default.size = NVS_FLASH_SECTOR_COUNT_MIN * SPI_FLASH_SEC_SIZE;
SpiFlashEmulator emu_other(10);
emu_other.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
esp_partition_t part_other = {};
strcpy(part_other.label, OTHER_PARTITION_NAME);
part_other.address = NVS_FLASH_SECTOR * SPI_FLASH_SEC_SIZE;
part_other.size = NVS_FLASH_SECTOR_COUNT_MIN * SPI_FLASH_SEC_SIZE;
const char* str = "value 0123456789abcdef0123456789abcdef";
const uint8_t blob[8] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
nvs_handle_t handle_1;
TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(NVS_DEFAULT_PART_NAME,
NVS_FLASH_SECTOR,
NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(NVSPartitionManager::get_instance()->init_custom(OTHER_PARTITION_NAME,
NVS_FLASH_SECTOR,
NVS_FLASH_SECTOR_COUNT_MIN));
TEST_ESP_OK(nvs_open_from_partition(OTHER_PARTITION_NAME, "ns", NVS_READWRITE, &handle_1));
// Deinitializing must not interfere with the open handle from the other partition.
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x3456789a));
nvs_close(handle_1);
TEST_ESP_OK(nvs_flash_deinit_partition(OTHER_PARTITION_NAME));
}