Просмотр исходного кода

Merge branch 'feature/nvs_erase_check_init_4.1' into 'release/v4.1'

NVS Flash: prevent erasing initialized partition, nvs partition deinit bug (backport v4.1)

See merge request espressif/esp-idf!10063
Ivan Grokhotkov 5 лет назад
Родитель
Сommit
f74bb4e5a9

+ 11 - 4
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
+ *
+ * @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 to be erased
+ * @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.
  *

+ 27 - 5
components/nvs_flash/src/nvs_api.cpp

@@ -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"
@@ -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) {

+ 4 - 0
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();
+}
+
 }

+ 2 - 0
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.

+ 27 - 11
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]")

+ 61 - 15
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();

+ 0 - 2
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;

+ 43 - 0
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));
+}

+ 1 - 1
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