From fe7ebf75a090e9f12af9d3b2ac713f81deaaeda3 Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Fri, 14 Feb 2020 15:09:22 +0100 Subject: [PATCH] NVS Flash: prevent erasing initialized partition Closes https://github.com/espressif/esp-idf/issues/4755 Closes https://github.com/espressif/esp-idf/issues/2777 Closes FCS-533 * nvs_flash_erase_partition() checks whether the parition in question is initialized already and will return an error if so * reflect changes in the documentation * nvs host unit tests now clean up after each test case nvs_flash: fixed deinit other partition's handles * When deinitializing or erasing a partition, nvs used to close all handles instead of only the current partition's handles. This is fixed now * Added a unit test for that case --- components/nvs_flash/include/nvs_flash.h | 15 +++- components/nvs_flash/src/nvs_api.cpp | 32 ++++++-- .../nvs_flash/src/nvs_handle_simple.cpp | 4 + .../nvs_flash/src/nvs_handle_simple.hpp | 2 + components/nvs_flash/test/test_nvs.c | 38 +++++++--- .../nvs_flash/test_nvs_host/test_nvs.cpp | 76 +++++++++++++++---- .../test_nvs_host/test_nvs_handle.cpp | 2 - .../test_nvs_host/test_nvs_initialization.cpp | 43 +++++++++++ tools/ci/config/target-test.yml | 2 +- 9 files changed, 176 insertions(+), 38 deletions(-) diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index a19f612b8f..eb5f2f9656 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -101,30 +101,37 @@ esp_err_t nvs_flash_deinit_partition(const char* partition_label); /** * @brief Erase the default NVS partition * - * This function erases all contents of the default NVS partition (one with label "nvs") + * Erases all contents of the default NVS partition (one with label "nvs"). + * + * @note If the partition is initialized, this function first de-initializes it. Afterwards, the partition has to + * be initialized again to be used. * * @return * - ESP_OK on success * - ESP_ERR_NOT_FOUND if there is no NVS partition labeled "nvs" in the * partition table + * - different error in case de-initialization fails (shouldn't happen) */ esp_err_t nvs_flash_erase(void); /** * @brief Erase specified NVS partition * - * This function erases all contents of specified NVS partition + * Erase all content of a specified NVS partition * - * @param[in] part_name Name (label) of the partition to be erased + * @note If the partition is initialized, this function first de-initializes it. Afterwards, the partition has to + * be initialized again to be used. + * + * @param[in] part_name Name (label) of the partition which should be erased * * @return * - ESP_OK on success * - ESP_ERR_NOT_FOUND if there is no NVS partition with the specified name * in the partition table + * - different error in case de-initialization fails (shouldn't happen) */ esp_err_t nvs_flash_erase_partition(const char *part_name); - /** * @brief Erase custom partition. * diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index a30b74ef77..b8987c7513 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -19,6 +19,7 @@ #include "nvs_partition_manager.hpp" #include "esp_partition.h" #include "sdkconfig.h" +#include #include "nvs_handle_simple.hpp" #ifdef CONFIG_NVS_ENCRYPTION #include "nvs_encr.hpp" @@ -95,7 +96,7 @@ extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSe { ESP_LOGD(TAG, "nvs_flash_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount); - return nvs::NVSPartitionManager::get_instance()->init_custom(partName, baseSector, sectorCount); + return NVSPartitionManager::get_instance()->init_custom(partName, baseSector, sectorCount); } #ifdef CONFIG_NVS_ENCRYPTION @@ -117,8 +118,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); @@ -144,7 +153,7 @@ extern "C" esp_err_t nvs_flash_init_partition(const char *part_name) Lock::init(); Lock lock; - return nvs::NVSPartitionManager::get_instance()->init_partition(part_name); + return NVSPartitionManager::get_instance()->init_partition(part_name); } extern "C" esp_err_t nvs_flash_init(void) @@ -182,6 +191,19 @@ extern "C" esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t* cfg) extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name) { + Lock::init(); + Lock lock; + + // if the partition is initialized, uninitialize it first + if (NVSPartitionManager::get_instance()->lookup_storage_from_name(part_name)) { + esp_err_t err = close_handles_and_deinit(part_name); + + // only hypothetical/future case, deinit_partition() only fails if partition is uninitialized + if (err != ESP_OK) { + return err; + } + } + const esp_partition_t* partition = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name); if (partition == NULL) { @@ -250,7 +272,7 @@ extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char* ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode); NVSHandleSimple *handle; - esp_err_t result = nvs::NVSPartitionManager::get_instance()->open_handle(part_name, name, open_mode, &handle); + esp_err_t result = NVSPartitionManager::get_instance()->open_handle(part_name, name, open_mode, &handle); if (result == ESP_OK) { NVSHandleEntry *entry = new NVSHandleEntry(handle, part_name); if (entry) { diff --git a/components/nvs_flash/src/nvs_handle_simple.cpp b/components/nvs_flash/src/nvs_handle_simple.cpp index 5a7b9e86e8..f3b37055a8 100644 --- a/components/nvs_flash/src/nvs_handle_simple.cpp +++ b/components/nvs_flash/src/nvs_handle_simple.cpp @@ -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(); +} + } diff --git a/components/nvs_flash/src/nvs_handle_simple.hpp b/components/nvs_flash/src/nvs_handle_simple.hpp index e05aaf7386..0f3a407fdc 100644 --- a/components/nvs_flash/src/nvs_handle_simple.hpp +++ b/components/nvs_flash/src/nvs_handle_simple.hpp @@ -76,6 +76,8 @@ public: bool nextEntry(nvs_opaque_iterator_t *it); + const char *get_partition_name() const; + private: /** * The underlying storage's object. diff --git a/components/nvs_flash/test/test_nvs.c b/components/nvs_flash/test/test_nvs.c index 50a297246e..529147e497 100644 --- a/components/nvs_flash/test/test_nvs.c +++ b/components/nvs_flash/test/test_nvs.c @@ -18,6 +18,28 @@ static const char* TAG = "test_nvs"; +TEST_CASE("flash erase deinitializes initialized partition", "[nvs]") +{ + nvs_handle_t handle; + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + nvs_flash_erase(); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + + TEST_ESP_OK(nvs_flash_init()); + TEST_ESP_OK(nvs_open("uninit_ns", NVS_READWRITE, &handle)); + nvs_close(handle); + TEST_ESP_OK(nvs_flash_erase()); + + // exptected: no partition is initialized since nvs_flash_erase() deinitialized the partition again + TEST_ESP_ERR(ESP_ERR_NVS_NOT_INITIALIZED, nvs_open("uninit_ns", NVS_READWRITE, &handle)); + + // just to be sure it's deinitialized in case of error and not affecting other tests + nvs_flash_deinit(); +} + // test could have different output on host tests TEST_CASE("nvs deinit with open handle", "[nvs]") { @@ -25,10 +47,7 @@ TEST_CASE("nvs deinit with open handle", "[nvs]") esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err); - const esp_partition_t* nvs_partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); - assert(nvs_partition && "partition table must have an NVS partition"); - ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } ESP_ERROR_CHECK( err ); @@ -43,10 +62,7 @@ TEST_CASE("various nvs tests", "[nvs]") esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err); - const esp_partition_t* nvs_partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); - assert(nvs_partition && "partition table must have an NVS partition"); - ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } ESP_ERROR_CHECK( err ); @@ -113,7 +129,7 @@ TEST_CASE("calculate used and free space", "[nvs]") const esp_partition_t* nvs_partition = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); assert(nvs_partition && "partition table must have an NVS partition"); - ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } ESP_ERROR_CHECK( err ); @@ -121,8 +137,8 @@ TEST_CASE("calculate used and free space", "[nvs]") // erase if have any namespace TEST_ESP_OK(nvs_get_stats(NULL, &stat1)); if(stat1.namespace_count != 0) { - TEST_ESP_OK(nvs_flash_erase()); TEST_ESP_OK(nvs_flash_deinit()); + TEST_ESP_OK(nvs_flash_erase()); TEST_ESP_OK(nvs_flash_init()); } @@ -235,8 +251,8 @@ TEST_CASE("calculate used and free space", "[nvs]") nvs_close(handle_3); - TEST_ESP_OK(nvs_flash_erase()); TEST_ESP_OK(nvs_flash_deinit()); + TEST_ESP_OK(nvs_flash_erase()); } TEST_CASE("check for memory leaks in nvs_set_blob", "[nvs]") diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index 07ec373033..31ca4fbf59 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -703,8 +703,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]") { @@ -864,6 +865,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]") @@ -898,6 +901,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]") @@ -905,7 +910,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); @@ -1039,6 +1043,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]") @@ -1092,6 +1097,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]") @@ -1111,6 +1118,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)); } @@ -1165,6 +1174,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); @@ -1448,6 +1459,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]") @@ -1505,6 +1518,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]") @@ -1523,6 +1538,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]") @@ -1695,6 +1712,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]") @@ -1716,6 +1735,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]") @@ -1733,6 +1754,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]") @@ -1754,6 +1778,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]") @@ -1889,6 +1915,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]") @@ -1917,6 +1945,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]") @@ -1958,6 +1988,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]") @@ -1971,6 +2003,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]") @@ -1985,6 +2019,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]") @@ -2004,6 +2040,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]") @@ -2032,6 +2070,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]") @@ -2050,6 +2090,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]") @@ -2069,6 +2111,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]") @@ -2085,6 +2129,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)); } @@ -2138,6 +2184,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]") @@ -2173,6 +2221,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]") @@ -2218,6 +2268,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]") @@ -2308,6 +2359,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]") @@ -2360,6 +2413,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]") @@ -2416,6 +2470,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) @@ -2481,6 +2537,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)); } @@ -2521,8 +2579,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(); @@ -2885,8 +2941,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]") @@ -3057,7 +3113,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++) { @@ -3125,7 +3180,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++) { @@ -3224,8 +3278,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; @@ -3236,8 +3288,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); @@ -3347,8 +3397,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++) { @@ -3360,8 +3408,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(); diff --git a/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp b/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp index bee7d823aa..c630d7bcf5 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs_handle.cpp @@ -45,7 +45,6 @@ TEST_CASE("NVSHandleSimple closes its reference in PartitionManager", "[partitio CHECK(NVSPartitionManager::get_instance()->open_handles_size() == 0); REQUIRE(NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK); - } TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[partition_mgr]") @@ -86,7 +85,6 @@ TEST_CASE("nvshandle readonly fails", "[partition_mgr]") { SpiFlashEmulator emu(10); - NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME); NVSHandleSimple *handle_1; NVSHandleSimple *handle_2; const uint32_t NVS_FLASH_SECTOR = 6; diff --git a/components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp b/components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp index c709922e6f..85e83afb66 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs_initialization.cpp @@ -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; @@ -45,4 +47,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)); +} diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index 2b1643b9cd..4ea69dac13 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -307,7 +307,7 @@ example_test_012: UT_001: extends: .unit_test_template - parallel: 32 + parallel: 33 tags: - ESP32_IDF - UT_T1_1