]> granicus.if.org Git - esp-idf/commitdiff
nvs: Fix recovery after power-off during erase operation
authorSagar Bijwe <sagar@espressif.com>
Fri, 13 Apr 2018 06:59:06 +0000 (12:29 +0530)
committerSagar Bijwe <sagar@espressif.com>
Tue, 17 Apr 2018 06:54:21 +0000 (12:24 +0530)
Current code for recovery after power-off do not clean-up partially
erased items for FULL pages. If the erasure was part of modification
operation, this gets luckily cleaned-up because of duplicate detection
logic. For erase-only operation, the problem still exists. This patch
adds the recovery for FULL pages also.

Closes TW<20284>

components/nvs_flash/src/nvs_page.cpp
components/nvs_flash/test_nvs_host/test_nvs.cpp

index 6b8d1fdacba20fa478c9907f7ee63e8519632279..cd0141f684d4d3d13c324105efb6c1457dee4e39 100644 (file)
@@ -590,6 +590,16 @@ esp_err_t Page::mLoadEntryTable()
             assert(item.span > 0);
 
             size_t span = item.span;
+
+            if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) {
+                for (size_t j = i + 1; j < i + span; ++j) {
+                    if (mEntryTable.get(j) != EntryState::WRITTEN) {
+                        eraseEntryAndSpan(i);
+                        break;
+                    }
+                }
+            }
+
             i += span - 1;
         }
 
index 19570e237e61b412cc5027f3466a5960b025106a..8b258de1b0eb1e5dc65119e235cd389fc3067173 100644 (file)
@@ -1402,8 +1402,33 @@ TEST_CASE("calculate used and free space", "[nvs]")
     nvs_close(handle_3);
 }
 
+TEST_CASE("Recovery from power-off when the entry being erased is not on active page", "[nvs]")
+{
+    const size_t blob_size = Page::BLOB_MAX_SIZE;
+    size_t read_size = blob_size;
+    uint8_t blob[blob_size] = {0x11};
+    SpiFlashEmulator emu(3);
+    TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3) );
+    nvs_handle handle;
+    TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
+
+    emu.clearStats();
+    emu.failAfter(2 * Page::BLOB_MAX_SIZE/4 + 36);
+    TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size) );
+    TEST_ESP_OK( nvs_set_blob(handle, "1b", blob, blob_size) );
+
+    TEST_ESP_ERR( nvs_erase_key(handle, "1a"), ESP_ERR_FLASH_OP_FAIL );
+
+    TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3) );
+
+    /* Check 1a is erased fully*/
+    TEST_ESP_ERR( nvs_get_blob(handle, "1a", blob, &read_size), ESP_ERR_NVS_NOT_FOUND);
 
+    /* Check 2b is still accessible*/
+    TEST_ESP_OK( nvs_get_blob(handle, "1b", blob, &read_size));
 
+    nvs_close(handle);
+}
 
 /* Add new tests above */
 /* This test has to be the final one */